There is GetBinaryType() for determining if an .exe file is 32-bit or 64-bit, but how can I do this for a .dll file? I want to ensure that a DLL is the right architecture before trying to load it with LoadLibrary().
if you want use dll for call functions or load resource from it - just try load it. if it was wrong architecture - you got error ERROR_BAD_EXE_FORMAT and dll wil be not loaded. check before this nothing more give. the try load is check already.
if you need check for some other reasons, exist several ways. most correct is next - open file, create image section from it and check section (last operation is undocumented)
HRESULT CheckImage( _In_ PCWSTR lpLibFileName, _Out_ PUSHORT Machine)
{
HANDLE hFile = CreateFileW(lpLibFileName, FILE_EXECUTE|FILE_READ_DATA, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
if (hFile != INVALID_HANDLE_VALUE)
{
HANDLE hSection = CreateFileMappingW(hFile, 0, PAGE_EXECUTE_READ|SEC_IMAGE, 0, 0, 0);
NtClose(hFile);
if (hSection)
{
SECTION_IMAGE_INFORMATION sii;
NTSTATUS status = ZwQuerySection(hSection, SectionImageInformation, &sii, sizeof(sii), 0);
NtClose(hSection);
*Machine = sii.Machine;
return status ? HRESULT_FROM_NT(status) : S_OK;
}
}
return HRESULT_FROM_WIN32(GetLastError());
}
you got or some error from this func (file not found, bad image, etc) or some IMAGE_FILE_MACHINE_*. usually IMAGE_FILE_MACHINE_AMD64 or IMAGE_FILE_MACHINE_I386
another way - use LoadLibraryExW with LOAD_LIBRARY_AS_DATAFILE and check IMAGE_NT_HEADERS of mapped image - really this way do all what first (including ZwQuerySection call internally) + mapped dll to memory - last is not need. so this is less efficient way.
HRESULT CheckImage2( _In_ PCWSTR lpLibFileName, _Out_ PUSHORT Machine)
{
if (HMODULE hmod = LoadLibraryExW(lpLibFileName, 0, LOAD_LIBRARY_AS_DATAFILE))
{
HRESULT hr = S_OK;
if (PIMAGE_NT_HEADERS pinth = RtlImageNtHeader(PAGE_ALIGN(hmod)))
{
*Machine = pinth->FileHeader.Machine;
}
else
{
hr = HRESULT_FROM_NT(STATUS_INVALID_IMAGE_NOT_MZ);
}
FreeLibrary(hmod);
return hr;
}
return HRESULT_FROM_WIN32(GetLastError());
}
else one way - direct read file and check it headers. this from one side is fastest, from another side - even if headers is correct - no guarantee that whole file is ok and not corrupted
HRESULT CheckImage3( _In_ PCWSTR lpLibFileName, _Out_ PUSHORT Machine, _Out_ PBOOL Is64Bit)
{
HANDLE hFile = CreateFileW(lpLibFileName, FILE_READ_DATA, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
if (hFile != INVALID_HANDLE_VALUE)
{
HRESULT hr = HRESULT_FROM_NT(STATUS_INVALID_IMAGE_NOT_MZ);
union {
IMAGE_DOS_HEADER idh;
IMAGE_NT_HEADERS inth;
};
OVERLAPPED ov {};
ULONG dwBytesRead;
if (ReadFile(hFile, &idh, sizeof(idh), &dwBytesRead, &ov))
{
if (dwBytesRead == sizeof(idh) && idh.e_magic == IMAGE_DOS_SIGNATURE)
{
hr = HRESULT_FROM_NT(STATUS_INVALID_IMAGE_FORMAT);
ov.Offset = idh.e_lfanew;
if (ReadFile(hFile, &inth, sizeof(inth), &dwBytesRead, &ov))
{
if (dwBytesRead == sizeof(inth) && inth.Signature == IMAGE_NT_SIGNATURE)
{
switch (inth.OptionalHeader.Magic)
{
case IMAGE_NT_OPTIONAL_HDR32_MAGIC:
*Is64Bit = FALSE;
hr = S_OK;
break;
case IMAGE_NT_OPTIONAL_HDR64_MAGIC:
*Is64Bit = TRUE;
hr = S_OK;
break;
}
*Machine = inth.FileHeader.Machine;
}
}
}
}
CloseHandle(hFile);
return hr;
}
return HRESULT_FROM_WIN32(GetLastError());
}
Related
I am trying to modify the existing AmCap application, available through Microsoft's SDK Direct Show samples, in order to get an image of the captured stream when I press the space button. Below is the point in which I am handling the space keydown.
case WM_KEYDOWN:
if((GetAsyncKeyState(VK_ESCAPE) & 0x01) && gcap.fCapturing)
{
StopCapture();
if(gcap.fWantPreview)
{
BuildPreviewGraph();
StartPreview();
}
}
else if ((GetAsyncKeyState(VK_SPACE) & 0x01))
{
IMediaControl *pMC = NULL;
HRESULT hr = gcap.pFg->QueryInterface(IID_IMediaControl, (void **)&pMC);
if (SUCCEEDED(hr)){
hr=pMC->Pause();
if (SUCCEEDED(hr)){
CaptureImage(TEXT("C:\\output.bmp"));
pMC->Run();
pMC->Release();
}else
ErrMsg(TEXT("Failed to pause stream! hr=0x%x"), hr);
}
else
ErrMsg(TEXT("Cannot grab image"));
}
break;
Below is the contents of the CaptureImage function.
HRESULT hr;
SmartPtr<IBasicVideo> pWC;
// If we got here, gcap.pVW is not NULL
ASSERT(gcap.pVW != NULL);
hr = gcap.pVW->QueryInterface(IID_IBasicVideo, (void**)&pWC);
if (pWC)
{
long bufSize;
long *lpCurrImage = NULL;
pWC->GetCurrentImage(&bufSize, NULL);
lpCurrImage = (long *)malloc(bufSize);
//
// Read the current video frame into a byte buffer. The information
// will be returned in a packed Windows DIB and will be allocated
// by the VMR.
hr = pWC->GetCurrentImage(&bufSize, lpCurrImage);
if (SUCCEEDED(hr))
{
HANDLE fh;
BITMAPFILEHEADER bmphdr;
BITMAPINFOHEADER bmpinfo;
DWORD nWritten;
memset(&bmphdr, 0, sizeof(bmphdr));
memset(&bmpinfo, 0, sizeof(bmpinfo));
bmphdr.bfType = ('M' << 8) | 'B';
bmphdr.bfSize = sizeof(bmphdr) + sizeof(bmpinfo) + bufSize;
bmphdr.bfOffBits = sizeof(bmphdr) + sizeof(bmpinfo);
bmpinfo.biSize = sizeof(bmpinfo);
bmpinfo.biWidth = 640;
bmpinfo.biHeight = 480;
bmpinfo.biPlanes = 1;
bmpinfo.biBitCount = 32;
fh = CreateFile(TEXT("C:\\Users\\mike\\Desktop\\output.bmp"),
GENERIC_WRITE, 0, NULL,
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
WriteFile(fh, &bmphdr, sizeof(bmphdr), &nWritten, NULL);
WriteFile(fh, &bmpinfo, sizeof(bmpinfo), &nWritten, NULL);
WriteFile(fh, lpCurrImage, bufSize, &nWritten, NULL);
CloseHandle(fh);
ErrMsg(TEXT("Captured current image to %s"), szFile);
return TRUE;
}
else
{
ErrMsg(TEXT("Failed to capture image! hr=0x%x"), hr);
return FALSE;
}
}
return FALSE;
The problem is that when I am trying to run the app, I receive an HRESULT (0x8000ffff) error when the GetCurrentImage function is being called.
On the other hand in case I execute the app through the VS debugger the code works just fine.
I tried to add a Sleep just after the stream pMC->Pause(), assuming that the problem was timing issue but that did not work.
Any ideas would be extremely helpful!
Thank you in advance.
I am trying to memory-map a file on Windows using VS2010.
I am doing this in a DLL.
The first instance of the DLL maps the file just fine.
The second instance within the same process causes
*ppvData = ::MapViewOfFile( *phMapping, FILE_MAP_READ, 0, 0, 0 );
to fail with the error "Not enough memory available for this command".
I am not sure why this happens.
If I map 2 different files instead of twice the same file, all works fine, so I don't trust the "Not enough memory" error message.
Thank you.
hr = MapFile(sPath, &m_hVoiceData, &m_pVoiceData,wsErr );
HRESULT CTTSEngObj::MapFile( wstring uPath, // Value that contains file path
HANDLE * phMapping, // Pointer to file mapping handle
void ** ppvData, // Pointer to the data
wstring &uError)
{
HRESULT hr = S_OK;
CSpDynamicString dstrFilePath(uPath.c_str());
if ( SUCCEEDED( hr ) )
{
bool fWorked = false;
*phMapping = NULL;
*ppvData = NULL;
HANDLE hFile;
#ifdef _WIN32_WCE
hFile = CreateFileForMapping( dstrFilePath, GENERIC_READ,
FILE_SHARE_READ, NULL, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL, NULL );
#else
hFile = CreateFile(CW2T(dstrFilePath), GENERIC_READ,
FILE_SHARE_READ, NULL, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL, NULL );
#endif
if (hFile != INVALID_HANDLE_VALUE)
{
*phMapping = ::CreateFileMapping( hFile, NULL, PAGE_READONLY, 0, 0, NULL );
if (*phMapping)
{
*ppvData = ::MapViewOfFile( *phMapping, FILE_MAP_READ, 0, 0, 0 );
if (*ppvData)
{
fWorked = true;
}
else
{
uError=GetLastErrorStdStrW();
}
}
else
{
uError=L"mapfile: fm failed";
}
::CloseHandle( hFile );
}
else
{
uError=L"mapfile: invalidhandle";
}
if (!fWorked)
{
hr = HRESULT_FROM_WIN32(::GetLastError());
if (*phMapping)
{
::CloseHandle(*phMapping);
*phMapping = NULL;
}
}
}
else
{
uError=L"mapfile: dynstr";
}
return hr;
} /* CTTSEngObj::MapFile */
And this is how it is declared:
class ATL_NO_VTABLE CTTSEngObj :
public CComObjectRootEx<CComMultiThreadModel>,
public CComCoClass<CTTSEngObj, &CLSID_SampleTTSEngine>,
public ISpTTSEngine,
public ISpObjectWithToken
{
private:
CComPtr<ISpObjectToken> m_cpToken;
HANDLE m_hVoiceData;
void* m_pVoiceData;
You request to map the entire file into memory. How big is it? There may very well not be a large enough contiguous range of unallocated process's address space.
I try to get command line parameters of another process in Windows 7. I'm using this article as reference.
But the return error gives me always (NTSTATUS dwStatus) negative number like:
dwStatus = -1073741820
the process ID is valid, and the apa = GetLastError(); is S_OK
here is my code:
header file
class NtDll
{
...
typedef DWORD (WINAPI *PNtQueryInformationProcess)(HANDLE, DWORD, PVOID, DWORD, PVOID );
static PNtQueryInformationProcess NtQueryInformationProcess;
....
....
}
c++ file
i do this to enable access :
//== only to have better chance to read processes =====
if(!sm_EnableTokenPrivilege(SE_DEBUG_NAME))
{
return 0;
}
// Attempt to access process
BOOL bReturnStatus = TRUE;
DWORD dwSize = 0;
DWORD dwSizeNeeded = 0;
DWORD dwBytesRead = 0;
DWORD dwBufferSize = 0;
HANDLE hHeap = 0;
WCHAR *pwszBuffer = NULL;
smPROCESSINFO spi = {0};
smPPROCESS_BASIC_INFORMATION pbi = NULL;
smPEB peb = {0};
smPEB_LDR_DATA peb_ldr = {0};
smRTL_USER_PROCESS_PARAMETERS peb_upp = {0};
ZeroMemory(&spi, sizeof(spi));
ZeroMemory(&peb, sizeof(peb));
ZeroMemory(&peb_ldr, sizeof(peb_ldr));
ZeroMemory(&peb_upp, sizeof(peb_upp));
// pSysProcess->dUniqueProcessId is the process number
HRESULT apa = 0;
HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION |
PROCESS_VM_READ, FALSE,pSysProcess->dUniqueProcessId);
if(hProcess == INVALID_HANDLE_VALUE) {
return FALSE;
}
else if(hProcess == NULL)
{
apa = GetLastError();
}
// Try to allocate buffer
hHeap = GetProcessHeap();
dwSize = sizeof(smPPROCESS_BASIC_INFORMATION);
pbi = (smPPROCESS_BASIC_INFORMATION)HeapAlloc(hHeap,
HEAP_ZERO_MEMORY,
dwSize);
// Did we successfully allocate memory
if(!pbi) {
CloseHandle(hProcess);
return FALSE;
}
// Attempt to get basic info on process
NTSTATUS dwStatus = NtDll::NtQueryInformationProcess(hProcess,
ProcessBasicInformation,
pbi,
dwSize,
&dwSizeNeeded);
HRESULT dwStatus_err = 0;
dwStatus_err = GetLastError(); // This gives me always access denied
all seems right but still I'm getting the wrong results any idea why ?
UPDATE:
i added the indication that i do sm_EnableTokenPrivilege
and :
dwStatus_err = GetLastError(); // This gives me always access denied
Simple way to get the command line parameters for processes:
WMIC path win32_process get Caption,Processid,Commandline
Another way via code (see this article):
VOID GetCommandLines()
{
HRESULT hr = 0;
IWbemLocator *WbemLocator = NULL;
IWbemServices *WbemServices = NULL;
IEnumWbemClassObject *EnumWbem = NULL;
// Step 1: --------------------------------------------------
// Initialize COM. ------------------------------------------
hr = CoInitializeEx(0, COINIT_MULTITHREADED);
// Step 2: --------------------------------------------------
// Set general COM security levels --------------------------
// Note: If you are using Windows 2000, you need to specify -
// the default authentication credentials for a user by using
// a SOLE_AUTHENTICATION_LIST structure in the pAuthList ----
// parameter of CoInitializeSecurity ------------------------
hr = CoInitializeSecurity(NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_DEFAULT, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE, NULL);
// Step 3: ---------------------------------------------------
// Obtain the initial locator to WMI -------------------------
hr = CoCreateInstance(CLSID_WbemLocator, 0, CLSCTX_INPROC_SERVER, IID_IWbemLocator, (LPVOID *) &WbemLocator);
// Step 4: -----------------------------------------------------
// Connect to WMI through the IWbemLocator::ConnectServer method
hr = WbemLocator->ConnectServer(L"ROOT\\CIMV2", NULL, NULL, NULL, 0, NULL, NULL, &WbemServices);
// Step 5: --------------------------------------------------
// Set security levels on the proxy -------------------------
hr = CoSetProxyBlanket(WbemServices, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, NULL, RPC_C_AUTHN_LEVEL_CALL, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE);
// Step 6: --------------------------------------------------
// Use the IWbemServices pointer to make requests of WMI ----
hr = WbemServices->ExecQuery(L"WQL", L"SELECT ProcessId,CommandLine FROM Win32_Process", WBEM_FLAG_FORWARD_ONLY, NULL, &EnumWbem);
// Step 7: -------------------------------------------------
// Get the data from the query in step 6 -------------------
if (EnumWbem != NULL) {
IWbemClassObject *result = NULL;
ULONG returnedCount = 0;
while((hr = EnumWbem->Next(WBEM_INFINITE, 1, &result, &returnedCount)) == S_OK) {
VARIANT ProcessId;
VARIANT CommandLine;
// access the properties
hr = result->Get(L"ProcessId", 0, &ProcessId, 0, 0);
hr = result->Get(L"CommandLine", 0, &CommandLine, 0, 0);
if (!(CommandLine.vt==VT_NULL))
wprintf(L"%u %s \r\n", ProcessId.uintVal, CommandLine.bstrVal);
result->Release();
}
}
// Cleanup
// ========
EnumWbem->Release();
WbemServices->Release();
WbemLocator->Release();
CoUninitialize();
getchar();
}
If you really want to get NtQueryInformationProcess working, see this blog entry, or this file.
DWORD GetRemoteCommandLineW(HANDLE hProcess, LPWSTR pszBuffer, UINT bufferLength)
{
struct RTL_USER_PROCESS_PARAMETERS_I
{
BYTE Reserved1[16];
PVOID Reserved2[10];
UNICODE_STRING ImagePathName;
UNICODE_STRING CommandLine;
};
struct PEB_INTERNAL
{
BYTE Reserved1[2];
BYTE BeingDebugged;
BYTE Reserved2[1];
PVOID Reserved3[2];
struct PEB_LDR_DATA* Ldr;
RTL_USER_PROCESS_PARAMETERS_I* ProcessParameters;
BYTE Reserved4[104];
PVOID Reserved5[52];
struct PS_POST_PROCESS_INIT_ROUTINE* PostProcessInitRoutine;
BYTE Reserved6[128];
PVOID Reserved7[1];
ULONG SessionId;
};
typedef NTSTATUS (NTAPI* NtQueryInformationProcessPtr)(
IN HANDLE ProcessHandle,
IN PROCESSINFOCLASS ProcessInformationClass,
OUT PVOID ProcessInformation,
IN ULONG ProcessInformationLength,
OUT PULONG ReturnLength OPTIONAL);
typedef ULONG (NTAPI* RtlNtStatusToDosErrorPtr)(NTSTATUS Status);
// Locating functions
HINSTANCE hNtDll = GetModuleHandleW(L"ntdll.dll");
NtQueryInformationProcessPtr NtQueryInformationProcess = (NtQueryInformationProcessPtr)GetProcAddress(hNtDll, "NtQueryInformationProcess");
RtlNtStatusToDosErrorPtr RtlNtStatusToDosError = (RtlNtStatusToDosErrorPtr)GetProcAddress(hNtDll, "RtlNtStatusToDosError");
if(!NtQueryInformationProcess || !RtlNtStatusToDosError)
{
printf("Functions cannot be located.\n");
return 0;
}
// Get PROCESS_BASIC_INFORMATION
PROCESS_BASIC_INFORMATION pbi;
ULONG len;
NTSTATUS status = NtQueryInformationProcess(
hProcess, ProcessBasicInformation, &pbi, sizeof(pbi), &len);
SetLastError(RtlNtStatusToDosError(status));
if(NT_ERROR(status) || !pbi.PebBaseAddress)
{
printf("NtQueryInformationProcess(ProcessBasicInformation) failed.\n");
return 0;
}
// Read PEB memory block
SIZE_T bytesRead = 0;
PEB_INTERNAL peb;
if(!ReadProcessMemory(hProcess, pbi.PebBaseAddress, &peb, sizeof(peb), &bytesRead))
{
printf("Reading PEB failed.\n");
return 0;
}
// Obtain size of commandline string
RTL_USER_PROCESS_PARAMETERS_I upp;
if(!ReadProcessMemory(hProcess, peb.ProcessParameters, &upp, sizeof(upp), &bytesRead))
{
printf("Reading USER_PROCESS_PARAMETERS failed.\n");
return 0;
}
if(!upp.CommandLine.Length)
{
printf("Command line length is 0.\n");
return 0;
}
// Check the buffer size
DWORD dwNeedLength = (upp.CommandLine.Length+1) / sizeof(wchar_t) +1;
if(bufferLength < dwNeedLength)
{
printf("Not enough buffer.\n");
return dwNeedLength;
}
// Get the actual command line
pszBuffer[dwNeedLength - 1] = L'\0';
if(!ReadProcessMemory(hProcess, upp.CommandLine.Buffer, pszBuffer, upp.CommandLine.Length, &bytesRead))
{
printf("Reading command line failed.\n");
return 0;
}
return bytesRead / sizeof(wchar_t);
}
I'm trying to add my software to registry, I have found some pieces of the codes I can use but not full working code C/C++ is new to me and can't create it on my own. But here is the basic idea: Check if reg key set if not create it.
I was able to get my program location using this code:
TCHAR szPath[MAX_PATH];
GetModuleFileName(NULL,szPath,MAX_PATH);
And was able to create the key with: (Not sure if it's the right way)
HKEY newValue;
RegOpenKey(HKEY_CURRENT_USER,"Software\\Microsoft\\Windows\\CurrentVersion\\Run",&newValue);
RegSetValueEx(newValue,"myprogram",0,REG_SZ,(LPBYTE)szPath,sizeof(szPath));
RegCloseKey(newValue);
return 0;
What is missing, A small check if the key isn't already there...
Thank you!
Here's some code that likely does what you want. Call RegisterProgram for your EXE to self-register itself for automatically being started when the user logs in. This function calls GetModuleFileName and then invokes another helper function called RegisterMyProgramForStartup that does the writing to the registry.
Call IsMyProgramRegisteredForStartup(L"My_Program") to detect if the registration actually exists and appears valid.
One quick note. The performance impact of checking to see if the key exists before actually writing it out again is negligible. You could just call RegisterProgram blindly and it will overwrite the key if it already exists. Detecting if the registration exists is useful for initializing your UI checkbox that enables or disables auto-start. (You are giving your users a choice, right? Because I hate apps that automatically install themselves to run automatically without giving me a choice.)
BOOL IsMyProgramRegisteredForStartup(PCWSTR pszAppName)
{
HKEY hKey = NULL;
LONG lResult = 0;
BOOL fSuccess = TRUE;
DWORD dwRegType = REG_SZ;
wchar_t szPathToExe[MAX_PATH] = {};
DWORD dwSize = sizeof(szPathToExe);
lResult = RegOpenKeyExW(HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\CurrentVersion\\Run", 0, KEY_READ, &hKey);
fSuccess = (lResult == 0);
if (fSuccess)
{
lResult = RegGetValueW(hKey, NULL, pszAppName, RRF_RT_REG_SZ, &dwRegType, szPathToExe, &dwSize);
fSuccess = (lResult == 0);
}
if (fSuccess)
{
fSuccess = (wcslen(szPathToExe) > 0) ? TRUE : FALSE;
}
if (hKey != NULL)
{
RegCloseKey(hKey);
hKey = NULL;
}
return fSuccess;
}
BOOL RegisterMyProgramForStartup(PCWSTR pszAppName, PCWSTR pathToExe, PCWSTR args)
{
HKEY hKey = NULL;
LONG lResult = 0;
BOOL fSuccess = TRUE;
DWORD dwSize;
const size_t count = MAX_PATH*2;
wchar_t szValue[count] = {};
wcscpy_s(szValue, count, L"\"");
wcscat_s(szValue, count, pathToExe);
wcscat_s(szValue, count, L"\" ");
if (args != NULL)
{
// caller should make sure "args" is quoted if any single argument has a space
// e.g. (L"-name \"Mark Voidale\"");
wcscat_s(szValue, count, args);
}
lResult = RegCreateKeyExW(HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\CurrentVersion\\Run", 0, NULL, 0, (KEY_WRITE | KEY_READ), NULL, &hKey, NULL);
fSuccess = (lResult == 0);
if (fSuccess)
{
dwSize = (wcslen(szValue)+1)*2;
lResult = RegSetValueExW(hKey, pszAppName, 0, REG_SZ, (BYTE*)szValue, dwSize);
fSuccess = (lResult == 0);
}
if (hKey != NULL)
{
RegCloseKey(hKey);
hKey = NULL;
}
return fSuccess;
}
void RegisterProgram()
{
wchar_t szPathToExe[MAX_PATH];
GetModuleFileNameW(NULL, szPathToExe, MAX_PATH);
RegisterMyProgramForStartup(L"My_Program", szPathToExe, L"-foobar");
}
int _tmain(int argc, _TCHAR* argv[])
{
RegisterProgram();
IsMyProgramRegisteredForStartup(L"My_Program");
return 0;
}
To check whether or not the value exists, call RegQueryValueEx.
LONG retval = RegQueryValueEx(hKey, "myprogram", NULL, NULL, NULL, NULL);
Note that what you called newValue is actually a key rather than a value. To avoid confusion you should name it such. I used the name hKey.
Then to check whether or not the value exists, compare retval against ERROR_SUCCESS as described in the documentation.
The other problem with your code is that there is absolutely no error checking. I'll leave that to you to address.
You forget to write an argument about security access
I'm in the process of making a security program for my network. One of it's instances is to check and monitor what api's and libraries are called. The dll to do that and the program that go along with it are already finished. But there is a problem that I cant seem to fix.
When trying to inject my dll into system processes (such as explorer.exe, my main test system process) with NtCreateThreadEx I get the return value: C0000022, it means something along the lines of: Status_Access_Denied (it returns in NTSTATUS, but DWORD will do)
I have no idea what to do, I'm running as Administrator, I raised my privileges, and used the proper functions, still I get c0000022
Here's the code I'm using to inject
#include "main.h"
typedef DWORD NTSTATUS;
struct NtCreateThreadExBuffer{
ULONG Size;
ULONG Unknown1;
ULONG Unknown2;
PULONG Unknown3;
ULONG Unknown4;
ULONG Unknown5;
ULONG Unknown6;
PULONG Unknown7;
ULONG Unknown8;
};
typedef NTSTATUS (WINAPI *LPFUN_NtCreateThreadEx)
(
OUT PHANDLE hThread,
IN ACCESS_MASK DesiredAccess,
IN LPVOID ObjectAttributes,
IN HANDLE ProcessHandle,
IN LPTHREAD_START_ROUTINE lpStartAddress,
IN LPVOID lpParameter,
IN BOOL CreateSuspended,
IN ULONG StackZeroBits,
IN ULONG SizeOfStackCommit,
IN ULONG SizeOfStackReserve,
OUT LPVOID lpBytesBuffer
);
using namespace std;
//#define CREATE_THREAD_ACCESS (PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ)
#define CREATE_THREAD_ACCESS ( PROCESS_ALL_ACCESS )
BOOL LoadDll(char *procName, char *dllName);
BOOL InjectDLL(DWORD dwProcessID, char *dllName);
BOOL LoadDll(char *dllName, DWORD dwProcID){
printf("Process Id to Inject: %d",dwProcID);
if(!dwProcID){
printf("No vailid PID\n");
return false;
}
FILE* FileCheck = fopen(dllName, "r");
if(FileCheck==NULL){
printf("\nUnable to inject %s", dllName);
return false;
}
fclose(FileCheck);
if(!InjectDLL(dwProcID, dllName)){
printf("injection failed\n");
return false;
} else {
return true;
}
}
BOOL InjectDLL(DWORD dwProcessID, char *dllName){
HANDLE hProc;
HANDLE hToken;
char buf[50]={0};
LPVOID RemoteString, LoadLibAddy;
if(!dwProcessID)return false;
HANDLE hCurrentProc = GetCurrentProcess();
if (!OpenProcessToken(hCurrentProc,TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,&hToken)){
printf("OpenProcessToken Error:%d\n", GetLastError());
} else {
if (!RaisePrivleges(hToken, (char*)SE_DEBUG_NAME)){
printf("SetPrivleges SE_DEBUG_NAME Error:%d\n", GetLastError());
}
}
if (hToken)CloseHandle(hToken);
hProc = OpenProcess(CREATE_THREAD_ACCESS, FALSE, dwProcessID);
printf("\nHandle to process: %x\n", hProc);
if(!hProc){
printf("OpenProcess() failed: %d", GetLastError());
return false;
}
LoadLibAddy = (LPVOID)GetProcAddress(GetModuleHandle("kernel32.dll"), "LoadLibraryA");
if(!LoadLibAddy){
printf("GetProcAddress() failed: %d", GetLastError());
return false;
}
RemoteString = (LPVOID)VirtualAllocEx(hProc, NULL, strlen(dllName), MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE);
if(RemoteString == NULL){
printf("VirtualAllocEx() failed: %d", GetLastError());
return false;
}
printf("\nRemote address: %x\n", RemoteString);
if(WriteProcessMemory(hProc, (LPVOID)RemoteString, dllName, strlen(dllName), NULL) == NULL){
printf("WriteProcessMemory() failed: %d", GetLastError());
return false;
}
/*
if(!CreateRemoteThread(hProc, NULL, NULL, (LPTHREAD_START_ROUTINE)LoadLibAddy, (LPVOID)RemoteString, NULL, NULL)){
printf("CreateRemoteThread() failed: %d", GetLastError());
return false;
}
*/
HMODULE modNtDll = GetModuleHandle("ntdll.dll");
if( !modNtDll )
{
printf("n failed to get module handle for ntdll.dll, Error=0x%.8x", GetLastError());
return 0;
}
LPFUN_NtCreateThreadEx funNtCreateThreadEx =
(LPFUN_NtCreateThreadEx) GetProcAddress(modNtDll, "NtCreateThreadEx");
if( !funNtCreateThreadEx )
{
printf("n failed to get function (NTCreateThreadEx) address from ntdll.dll, Error=0x%.8x\nTrying CreateRemoteThread api\n", GetLastError());
if(!CreateRemoteThread(hProc, NULL, NULL, (LPTHREAD_START_ROUTINE)LoadLibAddy, (LPVOID)RemoteString, NULL, NULL)){
printf("CreateRemoteThread() failed: %d", GetLastError());
return false;
} else {
printf("CreateRemoteThread success!\n");
return true;
}
return 0;
}
NtCreateThreadExBuffer ntbuffer;
memset (&ntbuffer,0,sizeof(NtCreateThreadExBuffer));
DWORD temp1 = 0;
DWORD temp2 = 0;
HANDLE pRemoteThread = NULL;
ntbuffer.Size = sizeof(NtCreateThreadExBuffer);
ntbuffer.Unknown1 = 0x10003;
ntbuffer.Unknown2 = 0x8;
ntbuffer.Unknown3 = &temp2;
ntbuffer.Unknown4 = 0;
ntbuffer.Unknown5 = 0x10004;
ntbuffer.Unknown6 = 4;
ntbuffer.Unknown7 = &temp1;
ntbuffer.Unknown8 = 0;
NTSTATUS status = funNtCreateThreadEx(
&pRemoteThread,
0x1FFFFF,
NULL,
hProc,
(LPTHREAD_START_ROUTINE) LoadLibAddy,
(LPVOID)RemoteString,
FALSE, //start instantly
NULL,
NULL,
NULL,
&ntbuffer
);
printf("NTCreateThreadEx return: %x\n", status);
// Resume the thread execution
WaitForSingleObject(pRemoteThread, INFINITE);
//Check the return code from remote thread function
DWORD dwExitCode;
if( GetExitCodeThread(pRemoteThread, (DWORD*) &dwExitCode) )
{
printf("\n Remote thread returned with status = %d\n", dwExitCode);
}
CloseHandle(pRemoteThread);
CloseHandle(hProc);
return true;
}
BOOL RaisePrivleges( HANDLE hToken, char *pPriv ){
TOKEN_PRIVILEGES tkp;
tkp.PrivilegeCount = 1;
tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
tkp.Privileges[0].Luid.HighPart = 0;
tkp.Privileges[0].Luid.LowPart = 0;
if (!LookupPrivilegeValue(NULL, pPriv, &tkp.Privileges[0].Luid)){
printf("LookupPrivilegeValue Error:%d\n", GetLastError());
return FALSE;
}
int iRet = AdjustTokenPrivileges(hToken, FALSE, &tkp, 0x10, (PTOKEN_PRIVILEGES)NULL, 0);
if (iRet == NULL){
printf( "AdjustTokenPrivileges Error:%d\n", GetLastError());
return TRUE;
} else {
iRet = GetLastError();
switch (iRet){
case ERROR_NOT_ALL_ASSIGNED:
printf("AdjustTokenPrivileges ERROR_NOT_ALL_ASSIGNED\n" );
return FALSE;
case ERROR_SUCCESS:
return TRUE;
default:
printf("AdjustTokenPrivileges Unknow Error:%d\n", iRet);
return FALSE;
}
}
}
1) If you're running on VISTA or later then you're possibly trying to inject into a 'protected process' from a 'non protected process'. See Process Security and Access Rights in MSDN. Non protected processes can't create threads in protected processes; though I must admit I'd expect the call to open process to fail when you request the inappropriate access rights rather than the subsequent create thread call to fail.
2) Why are you using NtCreateThreadEx() rather than simply calling CreateRemoteThread()?
3) This probably isn't the cause of your problem, but... You're failing to allocate memory for the null terminator in the string, you should be allocating strlen(dllName) + 1.
4) I assume that the process that is doing the injecting and the process that you're injecting into are both the same architecture, you're not running an x86 exe on x64 and expecting to inject into an x64 exe?
Since it's hard to find the right answer to this problem, I am posting even though the thread is old.
I was trying to inject into x64 service on Win7 x64 and kept running into same problems. My solution was:
Compile both the injector and injection dll as x64.
Instead of CreateRemoteThread & NtCreateThreadEx (both failing) use RtlCreateUserThread.
You must specify the full path to the injected DLL, otherwise it will not be found.