WSARecvFrom target ip address - c++

I use WSARecvFrom function. It looks like this:
addr.sin_addr.s_addr = INADDR_ANY;
addr.sin_port = htons(listen_port);
bind(s, reinterpret_cast<PSOCKADDR>(&addr), sizeof(addr));
...
WSARecvFrom(s, ..., reinterpret_cast<sockaddr *>(&event->address), &event->addressLength, ...);
I can read From IP address from event->address. But how can I read target IP address UDP packet was sent to (socket was binded to INADDR_ANY - it listens all interfaces) ?
UPDATE. I found solution (for Windows Vista and higher). I wrote 2 functions: WSARecvFromEx allows to get target IP and WSASendToEx allows to send "from" IP:
//copyright (c) 2013 Vitaly. http://blog.coolsoftware.ru/
#if !(_WIN32_WINNT >= 0x0501)
typedef
INT
(PASCAL FAR * LPFN_WSARECVMSG) (
__in SOCKET s,
__inout LPWSAMSG lpMsg,
__out_opt LPDWORD lpdwNumberOfBytesRecvd,
__inout_opt LPWSAOVERLAPPED lpOverlapped,
__in_opt LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
);
#define WSAID_WSARECVMSG \
{0xf689d7c8,0x6f1f,0x436b,{0x8a,0x53,0xe5,0x4f,0xe3,0x51,0xc3,0x22}}
#endif !(_WIN32_WINNT >= 0x0501)
#if !(_WIN32_WINNT >= 0x0600)
typedef
INT
(PASCAL FAR * LPFN_WSASENDMSG) (
__in SOCKET s,
__in LPWSAMSG lpMsg,
__in DWORD dwFlags,
__out_opt LPDWORD lpNumberOfBytesSent,
__inout_opt LPWSAOVERLAPPED lpOverlapped OPTIONAL,
__in_opt LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine OPTIONAL
);
#define WSAID_WSASENDMSG /* a441e712-754f-43ca-84a7-0dee44cf606d */ \
{0xa441e712,0x754f,0x43ca,{0x84,0xa7,0x0d,0xee,0x44,0xcf,0x60,0x6d}}
#endif !(_WIN32_WINNT >= 0x0600)
LPFN_WSARECVMSG pfWSARecvMsg = NULL;
LPFN_WSASENDMSG pfWSASendMsg = NULL;
int WSARecvFromEx(
SOCKET s,
LPWSABUF lpBuffers,
DWORD dwBufferCount,
LPDWORD lpNumberOfBytesRecvd,
LPDWORD lpFlags,
struct sockaddr FAR * lpFrom,
LPINT lpFromlen,
char * pControlBuffer,
ULONG nControlBufferLen,
LPWSAOVERLAPPED lpOverlapped,
LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
{
if (pControlBuffer != NULL &&
nControlBufferLen >= sizeof(WSACMSGHDR))
{
memset(pControlBuffer, 0, sizeof(WSACMSGHDR));
}
else
{
return WSARecvFrom(s, lpBuffers, dwBufferCount, lpNumberOfBytesRecvd, lpFlags, lpFrom, lpFromlen, lpOverlapped, lpCompletionRoutine);
}
if (pfWSARecvMsg == NULL)
{
return WSARecvFrom(s, lpBuffers, dwBufferCount, lpNumberOfBytesRecvd, lpFlags, lpFrom, lpFromlen, lpOverlapped, lpCompletionRoutine);
}
else
{
WSAMSG Msg;
Msg.name = lpFrom;
Msg.namelen = lpFromlen ? *lpFromlen : 0;
Msg.lpBuffers = lpBuffers;
Msg.dwBufferCount = dwBufferCount;
Msg.Control.buf = pControlBuffer;
Msg.Control.len = nControlBufferLen;
Msg.dwFlags = lpFlags ? *lpFlags : 0;
return pfWSARecvMsg(s, &Msg, lpNumberOfBytesRecvd, lpOverlapped, lpCompletionRoutine);
}
} //WSARecvFromEx()
int WSASendToEx(
SOCKET s,
LPWSABUF lpBuffers,
DWORD dwBufferCount,
LPDWORD lpNumberOfBytesSent,
DWORD dwFlags,
struct sockaddr FAR * lpTo,
int iTolen,
ULONG fromIp4,
char * pControlBuffer,
ULONG nControlBufferLen,
LPWSAOVERLAPPED lpOverlapped,
LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
{
int sum = 0;
if (fromIp4 != INADDR_ANY &&
pControlBuffer != NULL &&
nControlBufferLen >= WSA_CMSG_SPACE(sizeof(struct in_pktinfo)))
{
memset(pControlBuffer, 0, WSA_CMSG_SPACE(sizeof(struct in_pktinfo)));
WSACMSGHDR *pCMsgHdr = (WSACMSGHDR *)pControlBuffer;
pCMsgHdr->cmsg_level = IPPROTO_IP;
pCMsgHdr->cmsg_type = IP_PKTINFO;
pCMsgHdr->cmsg_len = WSA_CMSG_LEN(sizeof(struct in_pktinfo));
struct in_pktinfo *pktinfo = (struct in_pktinfo *)WSA_CMSG_DATA(pCMsgHdr);
pktinfo->ipi_addr.s_addr = htonl(fromIp4);
sum += WSA_CMSG_SPACE(sizeof(struct in_pktinfo));
}
else
{
return WSASendTo(s, lpBuffers, dwBufferCount, lpNumberOfBytesSent, dwFlags, lpTo, iTolen, lpOverlapped, lpCompletionRoutine);
}
if (pfWSASendMsg == NULL)
{
return WSASendTo(s, lpBuffers, dwBufferCount, lpNumberOfBytesSent, dwFlags, lpTo, iTolen, lpOverlapped, lpCompletionRoutine);
}
else
{
WSAMSG Msg;
Msg.name = lpTo;
Msg.namelen = iTolen;
Msg.lpBuffers = lpBuffers;
Msg.dwBufferCount = dwBufferCount;
Msg.Control.buf = pControlBuffer;
Msg.Control.len = sum;
Msg.dwFlags = dwFlags;
return pfWSASendMsg(s, &Msg, dwFlags, lpNumberOfBytesSent, lpOverlapped, lpCompletionRoutine);
}
} //WSASendToEx()
Initialization:
if (dwMajorVersion >= 6)
{
if (pfWSARecvMsg == NULL)
{
// get WSARecvMsg pointer
GUID WSARecvMsg_GUID = WSAID_WSARECVMSG;
DWORD NumberOfBytes = 0;
if (WSAIoctl(socket_, SIO_GET_EXTENSION_FUNCTION_POINTER,
&WSARecvMsg_GUID, sizeof(WSARecvMsg_GUID),
&pfWSARecvMsg, sizeof(pfWSARecvMsg),
&NumberOfBytes, NULL, NULL) == SOCKET_ERROR)
{
printf("Could not get WSARecvMsg. WSAGetLastError returned [%i]", WSAGetLastError());
pfWSARecvMsg = NULL;
}
}
if (pfWSASendMsg == NULL)
{
// get WSASendMsg pointer
GUID WSASendMsg_GUID = WSAID_WSASENDMSG;
DWORD NumberOfBytes = 0;
if (WSAIoctl(socket_, SIO_GET_EXTENSION_FUNCTION_POINTER,
&WSASendMsg_GUID, sizeof(WSASendMsg_GUID),
&pfWSASendMsg, sizeof(pfWSASendMsg),
&NumberOfBytes, NULL, NULL) == SOCKET_ERROR)
{
printf("Could not get WSASendMsg. WSAGetLastError returned [%i]", WSAGetLastError());
pfWSASendMsg = NULL;
}
}
}
Example of usage WSASendToEx:
int result = WSASendToEx(event->socket_, &sendBufferDescriptor, 1, &dwSent, 0,
reinterpret_cast<sockaddr *>(&event->address), event->addressLength,
from, event->controlBuffer, sizeof(event->controlBuffer),
&event->overlapped, NULL);
Example of usage WSARecvFromEx:
int result = WSARecvFromEx(event->socket_, &recvBufferDescriptor, 1,
&numberOfBytes, &recvFlags,
reinterpret_cast<sockaddr *>(&event->address), &event->addressLength,
event->controlBuffer, sizeof(event->controlBuffer),
&event->overlapped, NULL);

There is no way to get the target IP from WSARecvFrom() when bound to INADDR_ANY. If you need the target IP, you would have to create and bind a separate socket for each local IP that you want to receive on, then you can use getsockname() to know which local IP a receiving socket is bound to.

Related

How to start a new process as user "NT AUTHORITY\Network Service"?

I am trying to launch a new process as NT AUTHORITY\Network Service from a process that is running as NT AUTHORITY\System.
I have looked at other questions, such as the following, which does not provide a working example: CreateProcess running as user: "NT AUTHORITY/Network Service" without knowing the credentials?
And, I have come across some posts which talk about copying a token from a process that is already running as NT AUTHORITY\Network Service: Windows API and Impersonation Part 1 - How to get SYSTEM using Primary Tokens.
I wonder, is there a way to launch a process without having to depend on another process to copy a token from? Is there a way to hand-craft a token that can help launch a process as NT AUTHORITY\Network Service using CreateProcessAsUserW(), for example?
I came across a function LogonUser which can be used to create token for required user. The doc shows an example for creating token for NT AUTHORITY\LocalService like this:
LogonUser(L"LocalService", L"NT AUTHORITY", NULL, LOGON32_LOGON_SERVICE, LOGON32_PROVIDER_DEFAULT, &hToken)
I used the above in combination with CreateProcessAsUser function which starts child process as NT AUTHORITY\NetworkService where the parent is running as NT AUTHORITY\System
#include <Windows.h>
HANDLE token;
LogonUser(
L"NetworkService",
L"NT AUTHORITY",
nullptr,
LOGON32_LOGON_SERVICE,
LOGON32_PROVIDER_DEFAULT,
&token);
// Setup required variables to start the process
LPPROCESS_INFORMATION lpProcessInformation;
STARTUPINFOEX si;
PWCHAR path;
PCWSTR environmentBlockPtr = nullptr;
DWORD creationFlags;
WCHAR* commandStr;
CreateProcessAsUser(
token,
nullptr,
const_cast<WCHAR*>(commandStr),
nullptr,
nullptr,
FALSE,
creationFlags,
const_cast<WCHAR*>(environmentBlockPtr),
path,
&si.StartupInfo,
lpProcessInformation);
I suggest you do it via a scheduled task and then delete the task after it runs (or maybe there is a one-shot setting you could use). While System has the create token privilege the NtCreateToken function is not part of the documented API and using it would be an enormous pain. If not a scheduled task then as a service (again even if you are only going to run it once).
Is there a way to hand-craft a token that can help launch a process
as NT AUTHORITY\Network Service
yes. by call NtCreateToken. but for this need have SE_CREATE_TOKEN_PRIVILEGE. but services.exe and services, even running as 'NT AUTHORITY\System' have not it. so you can not just call NtCreateToken. first you need find token with this privilege and only after this.
for get token with required privileges set we can use next code:
extern const SECURITY_QUALITY_OF_SERVICE sqos = {
sizeof (sqos), SecurityImpersonation, SECURITY_DYNAMIC_TRACKING, FALSE
};
extern const OBJECT_ATTRIBUTES oa_sqos = { sizeof(oa_sqos), 0, 0, 0, 0, const_cast<SECURITY_QUALITY_OF_SERVICE*>(&sqos) };
NTSTATUS GetToken(_In_ PVOID buf, _In_ const TOKEN_PRIVILEGES* RequiredSet, _Out_ PHANDLE phToken)
{
NTSTATUS status;
union {
PVOID pv;
PBYTE pb;
PSYSTEM_PROCESS_INFORMATION pspi;
};
pv = buf;
ULONG NextEntryOffset = 0;
do
{
pb += NextEntryOffset;
HANDLE hProcess, hToken, hNewToken;
CLIENT_ID ClientId = { pspi->UniqueProcessId };
if (ClientId.UniqueProcess)
{
if (0 <= NtOpenProcess(&hProcess, PROCESS_QUERY_LIMITED_INFORMATION,
const_cast<POBJECT_ATTRIBUTES>(&oa_sqos), &ClientId))
{
status = NtOpenProcessToken(hProcess, TOKEN_DUPLICATE, &hToken);
NtClose(hProcess);
if (0 <= status)
{
status = NtDuplicateToken(hToken, TOKEN_ADJUST_PRIVILEGES|TOKEN_IMPERSONATE|TOKEN_QUERY,
const_cast<POBJECT_ATTRIBUTES>(&oa_sqos), FALSE, TokenImpersonation, &hNewToken);
NtClose(hToken);
if (0 <= status)
{
status = NtAdjustPrivilegesToken(hNewToken, FALSE, const_cast<PTOKEN_PRIVILEGES>(RequiredSet), 0, 0, 0);
if (STATUS_SUCCESS == status)
{
*phToken = hNewToken;
return STATUS_SUCCESS;
}
NtClose(hNewToken);
}
}
}
}
} while (NextEntryOffset = pspi->NextEntryOffset);
return STATUS_UNSUCCESSFUL;
}
NTSTATUS GetToken(_In_ const TOKEN_PRIVILEGES* RequiredSet, _Out_ PHANDLE phToken)
/*++
Routine Description:
try found process token with RequiredSet; duplicate and adjust privilege
Arguments:
RequiredSet - set of privileges which must be in token
phToken - Impersonation Token with all privileges from RequiredSet, all it is enabled (even if some is disabled in original token)
--*/
{
NTSTATUS status;
ULONG cb = 0x40000;
do
{
status = STATUS_INSUFFICIENT_RESOURCES;
if (PBYTE buf = new BYTE[cb += PAGE_SIZE])
{
if (0 <= (status = NtQuerySystemInformation(SystemProcessInformation, buf, cb, &cb)))
{
status = GetToken(buf, RequiredSet, phToken);
if (status == STATUS_INFO_LENGTH_MISMATCH)
{
status = STATUS_UNSUCCESSFUL;
}
}
delete [] buf;
}
} while(status == STATUS_INFO_LENGTH_MISMATCH);
return status;
}
with this we can do next:
#define BEGIN_PRIVILEGES(name, n) static const union { TOKEN_PRIVILEGES name;\
struct { ULONG PrivilegeCount; LUID_AND_ATTRIBUTES Privileges[n];} label(_) = { n, {
#define LAA(se) {{se}, SE_PRIVILEGE_ENABLED }
#define LAA_D(se) {{se} }
#define END_PRIVILEGES }};};
BEGIN_PRIVILEGES(tp_dbg, 2)
LAA(SE_DEBUG_PRIVILEGE), // need for open processes
LAA(SE_IMPERSONATE_PRIVILEGE), // need for impersonate token
END_PRIVILEGES
BEGIN_PRIVILEGES(tp_cai, 3)
LAA(SE_CREATE_TOKEN_PRIVILEGE),
LAA(SE_ASSIGNPRIMARYTOKEN_PRIVILEGE),
LAA(SE_INCREASE_QUOTA_PRIVILEGE),
END_PRIVILEGES
EXTERN_C NTSYSCALLAPI NTSTATUS NTAPI NtCreateToken(
_Out_ PHANDLE TokenHandle,
_In_ ACCESS_MASK DesiredAccess,
_In_opt_ POBJECT_ATTRIBUTES ObjectAttributes,
_In_ TOKEN_TYPE TokenType,
_In_ PLUID AuthenticationId,
_In_ PLARGE_INTEGER ExpirationTime,
_In_ PTOKEN_USER User,
_In_ PTOKEN_GROUPS Groups,
_In_ PTOKEN_PRIVILEGES Privileges,
_In_opt_ PTOKEN_OWNER Owner,
_In_ PTOKEN_PRIMARY_GROUP PrimaryGroup,
_In_opt_ PTOKEN_DEFAULT_DACL DefaultDacl,
_In_ PTOKEN_SOURCE TokenSource
);
NTSTATUS CreateServiceToken(HANDLE hToken, PHANDLE phToken)
{
NTSTATUS status;
PVOID stack = alloca(guz);
PVOID buf = 0;
ULONG cb = 0, rcb;
struct {
PTOKEN_GROUPS ptg;
PTOKEN_STATISTICS pts;
PTOKEN_DEFAULT_DACL ptdd;
PTOKEN_PRIVILEGES ptp;
} s;
void** ppv = (void**)&s.ptp;
static const ULONG rcbV[] = {
sizeof(TOKEN_GROUPS)+0x80,
sizeof(TOKEN_STATISTICS),
sizeof(TOKEN_DEFAULT_DACL)+0x80,
sizeof(TOKEN_PRIVILEGES)+0x80,
};
static TOKEN_INFORMATION_CLASS TokenInformationClassV[] = {
TokenGroups,
TokenStatistics,
TokenDefaultDacl,
TokenPrivileges,
};
ULONG n = _countof(TokenInformationClassV);
do
{
TOKEN_INFORMATION_CLASS TokenInformationClas = TokenInformationClassV[--n];
rcb = rcbV[n], cb = 0;
do
{
if (cb < rcb)
{
cb = RtlPointerToOffset(buf = alloca(rcb - cb), stack);
}
status = NtQueryInformationToken(hToken, TokenInformationClas, buf, cb, &rcb);
} while (status == STATUS_BUFFER_TOO_SMALL);
if (0 > status)
{
return status;
}
*(ppv--) = buf, stack = buf;
} while (n);
static const SID NetworkService = { SID_REVISION, 1, SECURITY_NT_AUTHORITY, { SECURITY_NETWORK_SERVICE_RID } };
static const TOKEN_OWNER to = { const_cast<SID*>(&NetworkService) };
static const TOKEN_USER tu = { { const_cast<SID*>(&NetworkService) } };
static const TOKEN_SOURCE ts = { {"Advapi"}, SYSTEM_LUID};
return NtCreateToken(phToken, TOKEN_ALL_ACCESS, 0, TokenPrimary,
&s.pts->AuthenticationId, &s.pts->ExpirationTime,
const_cast<PTOKEN_USER>(&tu), s.ptg, s.ptp, const_cast<PTOKEN_OWNER>(&to),
(PTOKEN_PRIMARY_GROUP)&to, s.ptdd, const_cast<PTOKEN_SOURCE>(&ts));
}
NTSTATUS RunAsNetworkService()
{
HANDLE hMyToken, hToken;
NTSTATUS status = NtOpenProcessToken(NtCurrentProcess(), TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY, &hMyToken);
if (0 <= status)
{
if (0 <= (status = NtAdjustPrivilegesToken(hMyToken, FALSE, const_cast<PTOKEN_PRIVILEGES>(&tp_dbg), 0, 0, 0)))
{
if (0 <= (status = GetToken(&tp_cai, &hToken)))
{
status = RtlSetCurrentThreadToken(hToken);
NtClose(hToken);
if (0 <= status)
{
if (0 <= (status = CreateServiceToken(hMyToken, &hToken)))
{
ULONG SessionId;
ProcessIdToSessionId(GetCurrentProcessId(), &SessionId);
if (0 <= (status = NtSetInformationToken(hToken, TokenSessionId, &SessionId, sizeof(SessionId))))
{
STARTUPINFO si = { sizeof(si) };
si.lpDesktop = const_cast<PWSTR>(L"WinSta0\\Default");
PROCESS_INFORMATION pi;
WCHAR cmdline[] = L"cmd /k whoami.exe /user";
if (CreateProcessAsUserW(hToken, 0, cmdline, 0, 0, 0, 0, 0, 0, &si, &pi))
{
NtClose(pi.hThread);
NtClose(pi.hProcess);
}
else
{
status = RtlGetLastNtStatus();
}
}
NtClose(hToken);
}
RtlSetCurrentThreadToken();
}
}
}
NtClose(hMyToken);
}
return status;
}
(code not use /RTCs )

I want to hook win32API CreateFileW by detours and print callstack information captured by CaptureStackBackTrace

I use detours to hook win32 api CreateFile and use CaptureStackBackTrace to get callstack information. and then resolve symbol by SymFromAddr api. but the result shown in terminal is only error 126 and error 184. And I only invoke ShowTraceStack function one time while trace information is more than one. I do not know what happened, can someone help me?
#include <windows.h>
#include <stdio.h>
#include "detours.h"
#include <fstream>
#include <Shlwapi.h>
#pragma comment(lib, "shlwapi.lib") //Windows API PathFileExists
#include <io.h>
#pragma comment(lib, "detours.lib")
#include <DbgHelp.h> //SymInitialize
#pragma comment(lib,"dbghelp.lib")
#define STACK_INFO_LEN 20000
struct stackInfo {
PDWORD hashValue; // hash value to identify same stack
char* szBriefInfo; // callstack info
};
stackInfo ShowTraceStack(char* szBriefInfo)
{
static const int MAX_STACK_FRAMES = 200;
void* pStack[MAX_STACK_FRAMES];
static char szStackInfo[STACK_INFO_LEN * MAX_STACK_FRAMES];
static char szFrameInfo[STACK_INFO_LEN];
HANDLE process = GetCurrentProcess(); // The handle used must be unique to avoid sharing a session with another component,
SymInitialize(process, NULL, TRUE);
PDWORD hashValue = (PDWORD)malloc(sizeof(DWORD)); // allow memory for hashVavlue, it will be rewrited in function CaptureStackBackTrace
WORD frames = CaptureStackBackTrace(0, MAX_STACK_FRAMES, pStack, hashValue);
//printf("hash value is: %ud \n", &hashValue);
if (szBriefInfo == NULL) {
strcpy_s(szStackInfo, "stack traceback:\n");
}
else {
strcpy_s(szStackInfo, szBriefInfo);
}
for (WORD i = 0; i < frames; ++i) {
DWORD64 address = (DWORD64)(pStack[i]);
DWORD64 displacementSym = 0;
char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(TCHAR)];
PSYMBOL_INFO pSymbol = (PSYMBOL_INFO)buffer;
pSymbol->SizeOfStruct = sizeof(SYMBOL_INFO);
pSymbol->MaxNameLen = MAX_SYM_NAME;
DWORD displacementLine = 0;
IMAGEHLP_LINE64 line;
line.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
if (SymFromAddr(process, address, &displacementSym, pSymbol) &&
SymGetLineFromAddr64(process, address, &displacementLine, &line))
{
_snprintf_s(szFrameInfo, sizeof(szFrameInfo), "\t%s() at %s:%d(0x%x)\n",
pSymbol->Name, line.FileName, line.LineNumber, pSymbol->Address);
}
else
{
_snprintf_s(szFrameInfo, sizeof(szFrameInfo), "\terror: %d\n", GetLastError());
}
strcat_s(szStackInfo, szFrameInfo);
}
stackInfo traceStackInfo;
traceStackInfo.hashValue = hashValue;
traceStackInfo.szBriefInfo = szStackInfo;
printf("%s", szStackInfo);
return traceStackInfo;
}
HANDLE(*oldCreateFile)(LPCWSTR,
DWORD,
DWORD,
LPSECURITY_ATTRIBUTES,
DWORD,
DWORD,
HANDLE) = CreateFileW;
HANDLE WINAPI newCreateFile(
_In_ LPCWSTR lpFileName,
_In_ DWORD dwDesiredAccess,
_In_ DWORD dwShareMode,
_In_opt_ LPSECURITY_ATTRIBUTES lpSecurityAttributes,
_In_ DWORD dwCreationDisposition,
_In_ DWORD dwFlagsAndAttributes,
_In_opt_ HANDLE hTemplateFile
) {
ShowTraceStack((char*)"trace information.");
return oldCreateFile(
L".\\newFiles.txt", // L".\\NewFile.txt", // Filename
//lpFileName,
dwDesiredAccess, // Desired access
dwShareMode, // Share mode
lpSecurityAttributes, // Security attributes
dwCreationDisposition, // Creates a new file, only if it doesn't already exist
dwFlagsAndAttributes, // Flags and attributes
NULL);
}
void hook() {
DetourRestoreAfterWith();
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
DetourAttach(&(PVOID&)oldCreateFile, newCreateFile);
DetourTransactionCommit();
}
void unhook()
{
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
DetourDetach(&(PVOID&)oldCreateFile, newCreateFile);
DetourTransactionCommit();
}
void myProcess() {
HANDLE hFile = CreateFile(TEXT(".\\CreateFileDemo.txt"),
GENERIC_WRITE | GENERIC_READ,
0,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (hFile == INVALID_HANDLE_VALUE)
{
OutputDebugString(TEXT("CreateFile fail!\r\n"));
}
// write to file
const int BUFSIZE = 4096;
char chBuffer[BUFSIZE];
memcpy(chBuffer, "Test", 4);
DWORD dwWritenSize = 0;
BOOL bRet = WriteFile(hFile, chBuffer, 4, &dwWritenSize, NULL);
ShowTraceStack((char*)"trace information.");
if (bRet)
{
OutputDebugString(TEXT("WriteFile success!\r\n"));
}
}
int main(){
hook();
myProcess();
unhook();
}

Getting thread name from NtQueryInformationThread

I'm trying to get thread name by ID, like this:
C Code:
NTSTATUS PhGetThreadName(
_In_ HANDLE ThreadHandle,
_Out_ PPH_STRING *ThreadName
)
{
NTSTATUS status;
PTHREAD_NAME_INFORMATION buffer;
ULONG bufferSize;
ULONG returnLength;
bufferSize = 0x100;
buffer = PhAllocate(bufferSize);
status = NtQueryInformationThread(
ThreadHandle,
ThreadNameInformation,
buffer,
bufferSize,
&returnLength
);
if (status == STATUS_BUFFER_OVERFLOW)
{
PhFree(buffer);
bufferSize = returnLength;
buffer = PhAllocate(bufferSize);
status = NtQueryInformationThread(
ThreadHandle,
ThreadNameInformation,
buffer,
bufferSize,
&returnLength
);
}
if (NT_SUCCESS(status))
{
*ThreadName = PhCreateStringFromUnicodeString(&buffer->ThreadName);
}
PhFree(buffer);
return status;
}
I want to implement this in C++ code.

How to import a PKCS#8 with CryptoApi

I Have a PKCS#8 Key and I desperately try to import in CryptoAPI without any success. I have :
-----BEGIN PRIVATE KEY-----
<privatekey>
-----END PRIVATE KEY-----
That contain this :
Private Key algo RSA
Private Format PKCS#8
ASN1 Dump
RSA Private CRT Key [.....]
modulus: .....
public exponent: .....
I try to import the key like this :
if not CryptStringToBinaryA(
PansiChar(aBase64PrivateKey), // pszString: LPCSTR;
length(aBase64PrivateKey), // cchString: DWORD;
CRYPT_STRING_BASE64HEADER, // dwFlags: DWORD;
nil, // pbBinary: pByte;
#cbPrivKey, // pcbBinary: PDWORD;
nil, // pdwSkip: PDWORD;
nil) then raiseLastOsError; // pdwFlags: PDWORD
setlength(pPrivKey, cbPrivKey);
if not CryptStringToBinaryA(
PansiChar(aBase64PrivateKey), // pszString: LPCSTR;
length(aBase64PrivateKey), // cchString: DWORD;
CRYPT_STRING_BASE64HEADER, // dwFlags: DWORD;
#pPrivKey[0], // pbBinary: pByte;
#cbPrivKey, // pcbBinary: PDWORD;
nil, // pdwSkip: PDWORD;
nil) then raiseLastOsError; // pdwFlags: PDWORD
//init pKeyBlob
if not CryptDecodeObjectEx(
X509_ASN_ENCODING or PKCS_7_ASN_ENCODING, // dwCertEncodingType: DWORD;
PKCS_PRIVATE_KEY_INFO, // lpszStructType: LPCSTR;
#pPrivKey[0], // const pbEncoded: PBYTE;
cbPrivKey, // cbEncoded: DWORD;
0, // dwFlags: DWORD;
nil, // pDecodePara: PCRYPT_DECODE_PARA;
nil, // pvStructInfo: Pointer;
#cbKeyBlob) then raiseLastOsError; // pcbStructInfo: PDWORD
setlength(pKeyBlob, cbKeyBlob);
if not CryptDecodeObjectEx(
X509_ASN_ENCODING or PKCS_7_ASN_ENCODING, // dwCertEncodingType: DWORD;
PKCS_PRIVATE_KEY_INFO, // lpszStructType: LPCSTR;
#pPrivKey[0], // const pbEncoded: PBYTE;
cbPrivKey, // cbEncoded: DWORD;
0, // dwFlags: DWORD;
nil, // pDecodePara: PCRYPT_DECODE_PARA;
#pKeyBlob[0], // pvStructInfo: Pointer;
#cbKeyBlob) then raiseLastOsError; // pcbStructInfo: PDWORD
//acquire a handle to a particular key container
if (not CryptAcquireContextA(#hProv, // phProv: PHCRYPTPROV;
nil, // pszContainer: PAnsiChar;
nil, // pszProvider: PAnsiChar;
PROV_RSA_AES, // dwProvType: DWORD;
CRYPT_VERIFYCONTEXT)) then raiselastOsError; // dwFlags: DWORD
try
// Now import the key.
if not CryptImportKey(hProv, // hProv: HCRYPTPROV;
#pKeyBlob[0], // const pbData: PBYTE;
cbKeyBlob, // dwDataLen: DWORD;
0, // hPubKey: HCRYPTKEY;
0, // dwFlags: DWORD;
#hRSAKey) then raiseLastOsError; // phKey: PHCRYPTKEY
but CryptImportKey fail with "Bad Version of provider", I guess because it's was waiting for a PKCS#1 Key. How can I import a PKCS#8 key?
for convert PKCS #8 format to legacy or CNG crypto api need several steps.
first need convert string to binary via CryptStringToBinaryA with CRYPT_STRING_BASE64HEADER
than call CryptDecodeObjectEx with PKCS_PRIVATE_KEY_INFO (if private key encrypted need use PKCS_ENCRYPTED_PRIVATE_KEY_INFO )
than need again call CryptDecodeObjectEx with PKCS_RSA_PRIVATE_KEY for legacy crypto api and CNG_RSA_PUBLIC_KEY_BLOB for CNG.
now we can call BCryptImportKeyPair or CryptImportKey
for import public key need use X509_PUBLIC_KEY_INFO, for public key from cert - X509_CERT_TO_BE_SIGNED (+ CNG_RSA_PUBLIC_KEY_BLOB for CNG, for legacy can use CryptImportPublicKeyInfo)
say code for legacy
inline ULONG BOOL_TO_ERROR(BOOL f)
{
return f ? NOERROR : GetLastError();
}
ULONG CryptImportPublicKey(_Out_ HCRYPTKEY *phKey,
_In_ HCRYPTPROV hProv,
_In_ PCUCHAR pbKeyOrCert,
_In_ ULONG cbKeyOrCert,
_In_ bool bCert)
{
ULONG cb;
union {
PVOID pvStructInfo;
PCERT_INFO pCertInfo;
PCERT_PUBLIC_KEY_INFO PublicKeyInfo;
};
ULONG dwError = BOOL_TO_ERROR(CryptDecodeObjectEx(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
bCert ? X509_CERT_TO_BE_SIGNED : X509_PUBLIC_KEY_INFO,
pbKeyOrCert, cbKeyOrCert, CRYPT_DECODE_ALLOC_FLAG|CRYPT_DECODE_NOCOPY_FLAG, 0, &pvStructInfo, &cb));
if (dwError == NOERROR)
{
PVOID pv = pvStructInfo;
if (bCert)
{
PublicKeyInfo = &pCertInfo->SubjectPublicKeyInfo;
}
dwError = BOOL_TO_ERROR(CryptImportPublicKeyInfo(hProv,
X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, PublicKeyInfo, phKey));
LocalFree(pv);
}
return dwError;
}
ULONG CryptImportPrivateKey(_Out_ HCRYPTKEY* phKey,
_In_ HCRYPTPROV hProv,
_In_ PCUCHAR pbKey,
_In_ ULONG cbKey)
{
ULONG cb;
PCRYPT_PRIVATE_KEY_INFO PrivateKeyInfo;
ULONG dwError = BOOL_TO_ERROR(CryptDecodeObjectEx(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, PKCS_PRIVATE_KEY_INFO,
pbKey, cbKey, CRYPT_DECODE_ALLOC_FLAG|CRYPT_DECODE_NOCOPY_FLAG, 0, (void**)&PrivateKeyInfo, &cb));
if (dwError == NOERROR)
{
PUBLICKEYSTRUC* ppks;
dwError = BOOL_TO_ERROR(CryptDecodeObjectEx(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
PKCS_RSA_PRIVATE_KEY, PrivateKeyInfo->PrivateKey.pbData, PrivateKeyInfo->PrivateKey.cbData,
CRYPT_DECODE_ALLOC_FLAG, 0, (void**)&ppks, &cb));
LocalFree(PrivateKeyInfo);
if (dwError == NOERROR)
{
dwError = BOOL_TO_ERROR(CryptImportKey(hProv, (PUCHAR)ppks, cb, 0, CRYPT_EXPORTABLE, phKey));
LocalFree(ppks);
}
}
return dwError;
}
enum BLOB_TYPE { bt_priv, bt_pub, bt_cert };
ULONG CryptImportKey(_Out_ HCRYPTKEY *phKey,
_In_ HCRYPTPROV hProv,
_In_ BLOB_TYPE bt,
_In_ PCSTR szKey,
_In_ ULONG cchKey)
{
PUCHAR pbKey = 0;
ULONG cbKey = 0;
ULONG dwError;
while (CryptStringToBinaryA(szKey, cchKey, CRYPT_STRING_BASE64HEADER, pbKey, &cbKey, 0, 0))
{
if (pbKey)
{
switch (bt)
{
case bt_priv:
dwError = CryptImportPrivateKey(phKey, hProv, pbKey, cbKey);
break;
case bt_pub:
dwError = CryptImportPublicKey(phKey, hProv, pbKey, cbKey, false);
break;
case bt_cert:
dwError = CryptImportPublicKey(phKey, hProv, pbKey, cbKey, true);
break;
default: dwError = ERROR_INVALID_PARAMETER;
}
_freea(pbKey);
return dwError;
}
if (!(pbKey = (PUCHAR)_malloca(cbKey)))
{
break;
}
}
dwError = GetLastError();
if (pbKey) _freea(pbKey);
return dwError;
}
void DoLegacyTest(_In_ PCSTR szToBeSigned,
_In_ PCSTR szPrivateKey,
_In_ ULONG cchPrivateKey,
_In_ PCSTR szPublicKeyOrCert,
_In_ ULONG cchPublicKeyOrCert,
_In_ bool bCert)
{
HCRYPTPROV hProv;
if (CryptAcquireContextW(&hProv, 0, MS_ENH_RSA_AES_PROV, PROV_RSA_AES, CRYPT_VERIFYCONTEXT))
{
HCRYPTKEY hKey;
HCRYPTHASH hHash;
if (CryptCreateHash(hProv, CALG_SHA_256, 0, 0, &hHash))
{
if (CryptHashData(hHash, (PUCHAR)szToBeSigned, (ULONG)strlen(szToBeSigned), 0))
{
PUCHAR pbSignature = 0;
ULONG cbSignature = 0;
BOOL fOk = false;
if (NOERROR == CryptImportKey(&hKey, hProv, bt_priv, szPrivateKey, cchPrivateKey))
{
ULONG dwKeySpec, cb;
if (CryptGetKeyParam(hKey, KP_ALGID, (PUCHAR)&dwKeySpec, &(cb = sizeof(dwKeySpec)), 0))
{
switch (dwKeySpec)
{
case CALG_RSA_KEYX:
dwKeySpec = AT_KEYEXCHANGE;
break;
case CALG_RSA_SIGN:
dwKeySpec = AT_SIGNATURE;
break;
default: dwKeySpec = 0;
}
if (CryptGetKeyParam(hKey, KP_BLOCKLEN, (PUCHAR)&cbSignature, &(cb = sizeof(cbSignature)), 0))
{
pbSignature = (PUCHAR)alloca(cbSignature >>= 3);
fOk = CryptSignHashW(hHash, dwKeySpec, 0, 0, pbSignature, &cbSignature);
}
}
CryptDestroyKey(hKey);
}
if (fOk)
{
if (NOERROR == CryptImportKey(&hKey, hProv, bCert ? bt_cert : bt_pub, szPublicKeyOrCert, cchPublicKeyOrCert))
{
if (!CryptVerifySignatureW(hHash, pbSignature, cbSignature, hKey, 0, 0))
{
__debugbreak();
}
CryptDestroyKey(hKey);
}
}
}
CryptDestroyHash(hHash);
}
CryptReleaseContext(hProv, 0);
}
}
code for CNG
inline ULONG BOOL_TO_ERROR(BOOL f)
{
return f ? NOERROR : GetLastError();
}
NTSTATUS openssl_verify(_In_ BCRYPT_KEY_HANDLE hKey,
_In_ PCUCHAR pbToBeSigned,
_In_ ULONG cbToBeSigned,
_In_ PCUCHAR pbSignature,
_In_ ULONG cbSignature,
_In_ PCWSTR pszAlgId)
{
BCRYPT_ALG_HANDLE hAlgorithm;
NTSTATUS status = BCryptOpenAlgorithmProvider(&hAlgorithm, pszAlgId, 0, 0);
if (0 <= status)
{
BCRYPT_HASH_HANDLE hHash = 0;
ULONG HashBlockLength, cb;
0 <= (status = BCryptGetProperty(hAlgorithm, BCRYPT_HASH_LENGTH, (PUCHAR)&HashBlockLength, sizeof(ULONG), &cb, 0)) &&
0 <= (status = BCryptCreateHash(hAlgorithm, &hHash, 0, 0, 0, 0, 0));
BCryptCloseAlgorithmProvider(hAlgorithm, 0);
if (0 <= status)
{
PUCHAR pbHash = (PUCHAR)alloca(HashBlockLength);
0 <= (status = BCryptHashData(hHash, const_cast<PUCHAR>(pbToBeSigned), cbToBeSigned, 0)) &&
0 <= (status = BCryptFinishHash(hHash, pbHash, HashBlockLength, 0));
BCryptDestroyHash(hHash);
if (0 <= status)
{
BCRYPT_PKCS1_PADDING_INFO pi = { pszAlgId };
status = BCryptVerifySignature(hKey, &pi, pbHash, HashBlockLength,
const_cast<PUCHAR>(pbSignature), cbSignature, BCRYPT_PAD_PKCS1);
}
}
}
return status;
}
inline NTSTATUS openssl_verify(_In_ BCRYPT_KEY_HANDLE hKey,
_In_ PCSTR szToBeSigned,
_In_ PCUCHAR pbSignature,
_In_ ULONG cbSignature,
_In_ PCWSTR pszAlgId)
{
return openssl_verify(hKey, (PCUCHAR)szToBeSigned, (ULONG)strlen(szToBeSigned), pbSignature, cbSignature, pszAlgId);
}
NTSTATUS openssl_sign(_In_ BCRYPT_KEY_HANDLE hKey,
_In_ PCUCHAR pbToBeSigned,
_In_ ULONG cbToBeSigned,
_Out_ PUCHAR pbSignature,
_Inout_ PULONG pcbSignature,
_In_ PCWSTR pszAlgId)
{
BCRYPT_ALG_HANDLE hAlgorithm;
NTSTATUS status = BCryptOpenAlgorithmProvider(&hAlgorithm, pszAlgId, 0, 0);
if (0 <= status)
{
BCRYPT_HASH_HANDLE hHash = 0;
ULONG HashBlockLength, cb;
0 <= (status = BCryptGetProperty(hAlgorithm, BCRYPT_HASH_LENGTH, (PUCHAR)&HashBlockLength, sizeof(ULONG), &cb, 0)) &&
0 <= (status = BCryptCreateHash(hAlgorithm, &hHash, 0, 0, 0, 0, 0));
BCryptCloseAlgorithmProvider(hAlgorithm, 0);
if (0 <= status)
{
PUCHAR pbHash = (PUCHAR)alloca(HashBlockLength);
0 <= (status = BCryptHashData(hHash, const_cast<PUCHAR>(pbToBeSigned), cbToBeSigned, 0)) &&
0 <= (status = BCryptFinishHash(hHash, pbHash, HashBlockLength, 0));
BCryptDestroyHash(hHash);
if (0 <= status)
{
BCRYPT_PKCS1_PADDING_INFO pi = { pszAlgId };
status = BCryptSignHash(hKey, &pi, pbHash, HashBlockLength,
pbSignature, *pcbSignature, pcbSignature, BCRYPT_PAD_PKCS1);
}
}
}
return status;
}
inline NTSTATUS openssl_sign(_In_ BCRYPT_KEY_HANDLE hKey,
_In_ PCSTR szToBeSigned,
_Out_ PUCHAR pbSignature,
_Inout_ PULONG pcbSignature,
_In_ PCWSTR pszAlgId)
{
return openssl_sign(hKey, (PCUCHAR)szToBeSigned, (ULONG)strlen(szToBeSigned), pbSignature, pcbSignature, pszAlgId);
}
NTSTATUS BCryptImportKey(_Out_ BCRYPT_KEY_HANDLE *phKey,
_In_ PCWSTR pszBlobType,
_In_ BCRYPT_RSAKEY_BLOB* prkb,
_In_ ULONG cb)
{
BCRYPT_ALG_HANDLE hAlgorithm;
NTSTATUS status = BCryptOpenAlgorithmProvider(&hAlgorithm, BCRYPT_RSA_ALGORITHM, 0, 0);
if (0 <= status)
{
status = BCryptImportKeyPair(hAlgorithm, 0, pszBlobType, phKey, (PUCHAR)prkb, cb, 0);
BCryptCloseAlgorithmProvider(hAlgorithm, 0);
}
return status;
}
HRESULT BCryptImportPrivateKey(_Out_ BCRYPT_KEY_HANDLE *phKey, _In_ PCUCHAR pbKey, _In_ ULONG cbKey)
{
ULONG cb;
PCRYPT_PRIVATE_KEY_INFO PrivateKeyInfo;
ULONG dwError = BOOL_TO_ERROR(CryptDecodeObjectEx(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, PKCS_PRIVATE_KEY_INFO,
pbKey, cbKey, CRYPT_DECODE_ALLOC_FLAG|CRYPT_DECODE_NOCOPY_FLAG, 0, (void**)&PrivateKeyInfo, &cb));
if (dwError == NOERROR)
{
BCRYPT_RSAKEY_BLOB* prkb;
dwError = BOOL_TO_ERROR(CryptDecodeObjectEx(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
CNG_RSA_PRIVATE_KEY_BLOB, PrivateKeyInfo->PrivateKey.pbData, PrivateKeyInfo->PrivateKey.cbData,
CRYPT_DECODE_ALLOC_FLAG, 0, (void**)&prkb, &cb));
LocalFree(PrivateKeyInfo);
if (dwError == NOERROR)
{
NTSTATUS status = BCryptImportKey(phKey, BCRYPT_RSAPRIVATE_BLOB, prkb, cb);
LocalFree(prkb);
return HRESULT_FROM_NT(status);
}
}
return HRESULT_FROM_WIN32(dwError);
}
HRESULT BCryptImportPublicKey(_Out_ BCRYPT_KEY_HANDLE *phKey, _In_ PCUCHAR pbKeyOrCert, _In_ ULONG cbKeyOrCert, _In_ bool bCert)
{
ULONG cb;
union {
PVOID pvStructInfo;
PCERT_INFO pCertInfo;
PCERT_PUBLIC_KEY_INFO PublicKeyInfo;
};
ULONG dwError = BOOL_TO_ERROR(CryptDecodeObjectEx(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
bCert ? X509_CERT_TO_BE_SIGNED : X509_PUBLIC_KEY_INFO,
pbKeyOrCert, cbKeyOrCert, CRYPT_DECODE_ALLOC_FLAG|CRYPT_DECODE_NOCOPY_FLAG, 0, &pvStructInfo, &cb));
if (dwError == NOERROR)
{
BCRYPT_RSAKEY_BLOB* prkb;
PVOID pv = pvStructInfo;
if (bCert)
{
PublicKeyInfo = &pCertInfo->SubjectPublicKeyInfo;
}
dwError = BOOL_TO_ERROR(CryptDecodeObjectEx(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
CNG_RSA_PUBLIC_KEY_BLOB,
PublicKeyInfo->PublicKey.pbData,
PublicKeyInfo->PublicKey.cbData,
CRYPT_DECODE_ALLOC_FLAG, 0, (void**)&prkb, &cb));
LocalFree(pv);
if (dwError == NOERROR)
{
NTSTATUS status = BCryptImportKey(phKey, BCRYPT_RSAPUBLIC_BLOB, prkb, cb);
LocalFree(prkb);
return HRESULT_FROM_NT(status);
}
}
return HRESULT_FROM_WIN32(dwError);
}
enum BLOB_TYPE { bt_priv, bt_pub, bt_cert };
HRESULT BCryptImportKey(_Out_ BCRYPT_KEY_HANDLE *phKey, _In_ BLOB_TYPE bt, _In_ PCSTR szKey, _In_ ULONG cchKey)
{
PUCHAR pbKey = 0;
ULONG cbKey = 0;
HRESULT hr;
while (CryptStringToBinaryA(szKey, cchKey, CRYPT_STRING_BASE64HEADER, pbKey, &cbKey, 0, 0))
{
if (pbKey)
{
switch (bt)
{
case bt_priv:
hr = BCryptImportPrivateKey(phKey, pbKey, cbKey);
break;
case bt_pub:
hr = BCryptImportPublicKey(phKey, pbKey, cbKey, false);
break;
case bt_cert:
hr = BCryptImportPublicKey(phKey, pbKey, cbKey, true);
break;
default: hr = E_INVALIDARG;
}
_freea(pbKey);
return hr;
}
if (!(pbKey = (PUCHAR)_malloca(cbKey)))
{
break;
}
}
hr = HRESULT_FROM_WIN32(GetLastError());
if (pbKey) _freea(pbKey);
return hr;
}
void DoCNGTest(_In_ PCSTR szToBeSigned,
_In_ PCSTR szPrivateKey,
_In_ ULONG cchPrivateKey,
_In_ PCSTR szPublicKeyOrCert,
_In_ ULONG cchPublicKeyOrCert,
_In_ bool bCert)
{
HRESULT hr;
BCRYPT_KEY_HANDLE hKey;
PUCHAR pbSignature = 0;
ULONG cbSignature = 0, cb;
if (0 <= (hr = BCryptImportKey(&hKey, bt_priv, szPrivateKey, cchPrivateKey)))
{
if (0 <= (hr = BCryptGetProperty(hKey, BCRYPT_SIGNATURE_LENGTH, (PUCHAR)&cbSignature, sizeof(ULONG), &cb, 0)))
{
pbSignature = (PUCHAR)alloca(cbSignature);
hr = HRESULT_FROM_NT(openssl_sign(hKey, szToBeSigned, pbSignature, &cbSignature, BCRYPT_SHA256_ALGORITHM));
}
BCryptDestroyKey(hKey);
}
if (0 <= hr)
{
if (0 <= (hr = BCryptImportKey(&hKey, bCert ? bt_cert : bt_pub, szPublicKeyOrCert, cchPublicKeyOrCert)))
{
hr = HRESULT_FROM_NT(openssl_verify(hKey, szToBeSigned, pbSignature, cbSignature, BCRYPT_SHA256_ALGORITHM));
if (0 > hr)
{
__debugbreak();
}
BCryptDestroyKey(hKey);
}
}
}

How to receive data send with DeviceIoControl at the Driver.c controlFunction? IOCTL,Driver

Let's say I have following code. Loading,unloading,driver entry etc works.
Driver.c
#define IO_INCREMENT_VALUE CTL_CODE(FILE_DEVICE_UNKNOWN, 0x0001, METHOD_BUFFERED, FILE_SPECIAL_ACCESS)
#define IO_RECEIVE_RANDOM_BUFFER CTL_CODE(FILE_DEVICE_UNKNOWN, 0x0002, METHOD_BUFFERED, FILE_SPECIAL_ACCESS)
NTSTATUS IoControl(PDEVICE_OBJECT DeviceObject, PIRP Irp)
{
NTSTATUS Status = STATUS_INVALID_PARAMETER;
ULONG BytesIO = 0;
const IO_STACK_LOCATION stack = *IoGetCurrentIrpStackLocation(Irp);
const ULONG ControlCode = stack.Parameters.DeviceIoControl.IoControlCode;
if (ControlCode == IO_INCREMENT_VALUE)
{
//How to receive LPVOID lpInBuffer,
// DWORD nInBufferSize,
// LPVOID lpOutBuffer,
// DWORD nOutBufferSize,
//send from DeviceIoControl
}
else if (ControlCode == IO_RECEIVE_RANDOM_BUFFER)
{
//How to receive LPVOID lpInBuffer,
// DWORD nInBufferSize,
// LPVOID lpOutBuffer,
// DWORD nOutBufferSize,
// /send from DeviceIoControl
/*
DWORD nOutBufferSize = ;
for(DWORD i = 0; i< nOutBufferSize; ++i)
{
}
*/
}
// Complete the request
Irp->IoStatus.Status = Status;
Irp->IoStatus.Information = BytesIO;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return Status;
}
and following UserMode.cpp
constexpr auto IO_INCREMENT_VALUE CTL_CODE(FILE_DEVICE_UNKNOWN, 0x0001, METHOD_BUFFERED, FILE_SPECIAL_ACCESS);
constexpr auto IO_RECEIVE_RANDOM_BUFFER CTL_CODE(FILE_DEVICE_UNKNOWN, 0x0002, METHOD_BUFFERED, FILE_SPECIAL_ACCESS);
int main()
{
//Find our Driver we want to Communicate with
//https://learn.microsoft.com/de-de/windows/win32/api/fileapi/nf-fileapi-createfilea
const LPCSTR lpFileName = R"(\\.\test)"; //Equals the Name we specified at DriverEntry
const DWORD dwDesiredAccess = GENERIC_ALL;
const DWORD dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
const LPSECURITY_ATTRIBUTES lpSecurityAttributes = nullptr;
const DWORD dwCreationDisposition = OPEN_EXISTING;
const DWORD dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL;
const HANDLE hTemplateFile = nullptr;
const HANDLE driver = CreateFile(
lpFileName,
dwDesiredAccess,
dwShareMode,
lpSecurityAttributes,
dwCreationDisposition,
dwFlagsAndAttributes,
hTemplateFile
);
if (driver == INVALID_HANDLE_VALUE)
{
return GetLastError();
}
//Example 1: Send an uint64_t and receive the value + 1.
uint64_t in_example1 = 1;
uint64_t out_example1 = 0;
LPDWORD lpBytesReturned = nullptr;
DeviceIoControl(driver, IO_INCREMENT_VALUE, &in_example1,
sizeof(in_example1), &out_example1, sizeof(out_example1), lpBytesReturned, nullptr);
std::cout << out_example1 << "\n"; //should return 2
//Example 2: Get a buffer with random values. Should be later the readMemory()
const UINT_PTR bytes_to_be_read = 357096;
//Any Buffer should be possible
char* data = new char[bytes_to_be_read];
uint64_t* data2 = new uint64_t[bytes_to_be_read];
DeviceIoControl(driver, IO_RECEIVE_RANDOM_BUFFER, nullptr,
0, data, bytes_to_be_read, lpBytesReturned, nullptr);
//should return data or data2 with some random values
}
"The DeviceIoControl function provides a device input and output control (IOCTL) interface through which an application can communicate directly with a device driver."
But How do i receive
LPVOID lpInBuffer,
DWORD nInBufferSize,
LPVOID lpOutBuffer,
DWORD nOutBufferSize,
send from DeviceIoControl inside the Driver.c I/O function?
For completness:
Links used:
https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/ns-wdm-_irp
https://learn.microsoft.com/en-us/windows/win32/api/ioapiset/nf-ioapiset-deviceiocontrol
https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/ns-wdm-_io_stack_location
The IO_STACK_LOCATION just provides access to
Parameters.DeviceIoControl
Parameters.DeviceIoControl.OutputBufferLength
Parameters.DeviceIoControl.InputBufferLength
Parameters.DeviceIoControl.IoControlCode
Parameters.DeviceIoControl.Type3InputBuffer
By using Buffer I/O method, the I/O Manager allocates the input buffer to non-paged pool and stores a pointer to that memory inside Irp->AssociatedIrp.SystemBuffer, Only then IoContorl will start.
Later, when the request completes, the I/O Manager takes that SystemBuffer and copies the amount of bytes (according to Irp->IoStatus.Information) to the output buffer.
With that said, here's the solution:
#define IO_INCREMENT_VALUE CTL_CODE(FILE_DEVICE_UNKNOWN, 0x0001, METHOD_BUFFERED, FILE_SPECIAL_ACCESS)
#define IO_RECEIVE_RANDOM_BUFFER CTL_CODE(FILE_DEVICE_UNKNOWN, 0x0002, METHOD_BUFFERED, FILE_SPECIAL_ACCESS)
NTSTATUS IoControl(PDEVICE_OBJECT DeviceObject, PIRP Irp)
{
NTSTATUS Status = STATUS_INVALID_PARAMETER;
ULONG BytesIO = 0;
const IO_STACK_LOCATION stack = *IoGetCurrentIrpStackLocation(Irp);
const ULONG ControlCode = stack.Parameters.DeviceIoControl.IoControlCode;
if (ControlCode == IO_INCREMENT_VALUE)
{
// Check input buffer size
ULONG bytes = stack.Parameters.DeviceIoControl.InputBufferLength;
if (bytes < sizeof(long long)) {
// Error - should complete the request
Irp->IoStatus.Status = STATUS_INVALID_BUFFER_SIZE;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
// Must return the same value as Irp.IoStatus.Status
return STATUS_INVALID_BUFFER_SIZE;
}
long long* input = (long long*)Irp->AssociatedIrp.SystemBuffer;
InterlockedAdd64(input, 1);
// Same SystemBuffer is used for input and output so we just need
// to complete the request with the appropriate bytes written.
Status = STATUS_SUCCESS;
BytesIO = sizeof(*input);
}
else if (ControlCode == IO_RECEIVE_RANDOM_BUFFER)
{
// Check input buffer size
ULONG bytes = stack.Parameters.DeviceIoControl.InputBufferLength;
if (bytes == 0) {
// Error - should complete the request
Irp->IoStatus.Status = STATUS_INVALID_BUFFER_SIZE;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
// Must return the same value as Irp.IoStatus.Status
return STATUS_INVALID_BUFFER_SIZE;
}
PVOID buffer = Irp->AssociatedIrp.SystemBuffer;
memset(buffer, 0, bytes);
Status = STATUS_SUCCESS;
BytesIO = bytes;
}
// Complete the request
Irp->IoStatus.Status = Status;
Irp->IoStatus.Information = BytesIO;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return Status;
}