Detours DLL injection works only for specific applications - windows

I try to hook some functions using Microsoft Detours. The method I'm using is CreateRemoteThread + LoadLibrary.
Yet, I've encountered that the exact same code works on notepad.exe, some chrome processes etc., but not on wmplayer.exe(Windows Media Player), Calculator.exe somehow. Is it correct to say that these applications probably tried to prevent this type of DLL injection? I can hardly come up with other possibilities.
Most of these code are copied from the Detours tutorial
The code can be seen and cloned from this repository in case anyone want to experiment them.
DLL:
INT APIENTRY DllMain(HMODULE hDLL, DWORD Reason, LPVOID Reserved)
{
try {
std::ofstream file("D:\\output.txt");
file << "Hello!\n";
file.close();
}
catch (...) {
std::ofstream file("D:\\error.txt");
file << "Hello!\n";
file.close();
}
}
Injector:
int main(void)
{
if (fileExists("D:\\output.txt"))
{
printf("Removing...\n");
remove("D:\\output.txt");
}
PROCESSENTRY32 pe32;
pe32.dwSize = sizeof(PROCESSENTRY32);
HANDLE hTool32 = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);
if (Process32First(hTool32, &pe32))
{
while ((Process32Next(hTool32, &pe32)) == TRUE) {
char exeName[] = "Calculator.exe";
//char exeName[] = "notepad.exe";
if (strcmp(pe32.szExeFile, exeName) == 0)
{
printf("Found %s at %d\n", exeName, pe32.th32ProcessID);
char* DirPath = new char[MAX_PATH];
char* FullPath = new char[MAX_PATH];
GetCurrentDirectory(MAX_PATH, DirPath);
sprintf_s(FullPath, MAX_PATH, "%s\\..\\x64\\Debug\\TestDLL.dll", DirPath);
printf("%s File exists: %d\n", FullPath, fileExists(FullPath));
HANDLE hProcess = OpenProcess(
PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ, FALSE, pe32.th32ProcessID);
LPVOID LoadLibraryAddr = (LPVOID)GetProcAddress(GetModuleHandle("kernel32.dll"), "LoadLibraryA");
LPVOID LLParam = (LPVOID)VirtualAllocEx(hProcess, NULL, strlen(FullPath),
MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
BOOL status = WriteProcessMemory(hProcess, LLParam, FullPath, strlen(FullPath), NULL);
auto handle = CreateRemoteThread(hProcess, NULL, NULL, (LPTHREAD_START_ROUTINE)LoadLibraryAddr,
LLParam, NULL, NULL);
CloseHandle(hProcess);
delete[] DirPath;
delete[] FullPath;
std::cin.get();
}
}
}
CloseHandle(hTool32);
return 0;
}
when the variable exeName is set to "notepad.exe", the file "D:\output.txt" will be created, while setting the variable to "Calculator.exe" won't.
If my guess is correct, is using other injection method(ex. SetWindowsHookEx) the only way I can make these work?

On Windows 10, "Calculator" is Windows App and according to Detours documentation detours doesn't work for Windows App for following reason
Why can't my Windows Store app for Windows 8 include Detours?
Windows Store apps may use only a subset of the Win32 API. Detours
requires several Win32 APIs that are forbidden in for Windows App
Certification. Forbidden APIs used by Detours include VirtualAlloc,
VirtualProtect, and FlushInstructionCache.
As per Microsoft documentation
Windows apps:: All apps installed in C:\Program Files\WindowsApps.
Path of "Calculator" on Windows 10 is
C:\Program
Files\WindowsApps\microsoft.windowscalculator_10.2103.8.0_x64__8wekyb3d8bbwe\Calculator.exe

Personally I think these applications indeed prevented from being injected by the CreateRemoteThread + LoadLibrary method since it's the most basic approach, but this guess needs further proof. After I switched to use the SetWindowsHookEX method in this repository, the DllMain will be called successfully.

Related

Walking the NTFS Change Journal on Windows 10

I'm trying to read the NTFS Change Journal but I've noticed that all the example code I can find fails on Windows 10, even though it works on Windows 7.
For example, Microsofts own example Walking a Buffer of Change Journal Records works on Windows 7 but when I run the same code on Windows 10 I get an error 87 (The parameter is incorrect) when I call DeviceIoControl with FSCTL_READ_USN_JOURNAL (Note that the earlier call to DeviceIoControl with FSCTL_QUERY_USN_JOURNAL completes successfully and return valid data.).
I've even taken the EXE compiled and working on Windows 7 and copied it to the Windows 10 machine and it still fails, so I believe that Windows 10 may be more strict on parameter validation or something like that?
I am running the code as Administrator, so that's not the issue.
I can't find any other references to this problem, but I get the same issue if I take other peoples example code and attempt to run it on Windows 10.
Edit:
The code itself:
#include <Windows.h>
#include <WinIoCtl.h>
#include <stdio.h>
#define BUF_LEN 4096
void main()
{
HANDLE hVol;
CHAR Buffer[BUF_LEN];
USN_JOURNAL_DATA JournalData;
READ_USN_JOURNAL_DATA ReadData = {0, 0xFFFFFFFF, FALSE, 0, 0};
PUSN_RECORD UsnRecord;
DWORD dwBytes;
DWORD dwRetBytes;
int I;
hVol = CreateFile( TEXT("\\\\.\\c:"),
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
0,
NULL);
if( hVol == INVALID_HANDLE_VALUE )
{
printf("CreateFile failed (%d)\n", GetLastError());
return;
}
if( !DeviceIoControl( hVol,
FSCTL_QUERY_USN_JOURNAL,
NULL,
0,
&JournalData,
sizeof(JournalData),
&dwBytes,
NULL) )
{
printf( "Query journal failed (%d)\n", GetLastError());
return;
}
ReadData.UsnJournalID = JournalData.UsnJournalID;
printf( "Journal ID: %I64x\n", JournalData.UsnJournalID );
printf( "FirstUsn: %I64x\n\n", JournalData.FirstUsn );
for(I=0; I<=10; I++)
{
memset( Buffer, 0, BUF_LEN );
if( !DeviceIoControl( hVol,
FSCTL_READ_USN_JOURNAL,
&ReadData,
sizeof(ReadData),
&Buffer,
BUF_LEN,
&dwBytes,
NULL) )
{
printf( "Read journal failed (%d)\n", GetLastError());
return;
}
dwRetBytes = dwBytes - sizeof(USN);
// Find the first record
UsnRecord = (PUSN_RECORD)(((PUCHAR)Buffer) + sizeof(USN));
printf( "****************************************\n");
// This loop could go on for a long time, given the current buffer size.
while( dwRetBytes > 0 )
{
printf( "USN: %I64x\n", UsnRecord->Usn );
printf("File name: %.*S\n",
UsnRecord->FileNameLength/2,
UsnRecord->FileName );
printf( "Reason: %x\n", UsnRecord->Reason );
printf( "\n" );
dwRetBytes -= UsnRecord->RecordLength;
// Find the next record
UsnRecord = (PUSN_RECORD)(((PCHAR)UsnRecord) +
UsnRecord->RecordLength);
}
// Update starting USN for next call
ReadData.StartUsn = *(USN *)&Buffer;
}
CloseHandle(hVol);
}
I've managed to work out what the problem is.
The example Microsoft code creates a local variable defined as READ_USN_JOURNAL_DATA, which is defined as:
#if (NTDDI_VERSION >= NTDDI_WIN8)
typedef READ_USN_JOURNAL_DATA_V1 READ_USN_JOURNAL_DATA, *PREAD_USN_JOURNAL_DATA;
#else
typedef READ_USN_JOURNAL_DATA_V0 READ_USN_JOURNAL_DATA, *PREAD_USN_JOURNAL_DATA;
#endif
On my systems (Both the Win10 and Win7 systems) this evaluates to READ_USN_JOURNAL_DATA_V1.
Looking at the difference betweem READ_USN_JOURNAL_DATA_V0 and READ_USN_JOURNAL_DATA_V1 we can see that V0 is defined as:
typedef struct {
USN StartUsn;
DWORD ReasonMask;
DWORD ReturnOnlyOnClose;
DWORDLONG Timeout;
DWORDLONG BytesToWaitFor;
DWORDLONG UsnJournalID;
} READ_USN_JOURNAL_DATA_V0, *PREAD_USN_JOURNAL_DATA_V0;
and the V1 version is defined as:
typedef struct {
USN StartUsn;
DWORD ReasonMask;
DWORD ReturnOnlyOnClose;
DWORDLONG Timeout;
DWORDLONG BytesToWaitFor;
DWORDLONG UsnJournalID;
WORD MinMajorVersion;
WORD MaxMajorVersion;
} READ_USN_JOURNAL_DATA_V1, *PREAD_USN_JOURNAL_DATA_V1;
Note the new Min and Max Major version members.
So, the Microsoft code is defining a local variable called ReadData that is actually a V1 structure, yet it appears to fill in the data assuming it's a V0 structure. i.e. it doesn't set the Min and Max elements.
It appears that Win7 is fine with this but Win10 rejects it and returns error 87 (The parameter is incorrect).
Sure enough if I explicitly define the ReadData variable to be a READ_USN_JOURNAL_DATA_V0 then the code works on Win7 and Win10, whereas if I explicitly define it as a READ_USN_JOURNAL_DATA_V1 then it continues to work on Win7 but not on Win10.
The strange thing is that the API documentation for READ_USN_JOURNAL_DATA_V1 structure states that it's only supported from Windows 8 on, so it's odd that it works on Windows 7 at all. I guess it's just interpreting it as a READ_USN_JOURNAL_DATA_V0 structure given that V1 version is an extension of the V0 structure. If so then it must be ignoring the size parameter that is passed into DeviceIOControl.
Anyway, all working now. I hope someone finds this a useful reference in the future.
I came across this exact same issue with the sample code as the OP. At the start of the sample code, you will see a partial initialization of the structure at the point of declaration. A little later in the code, right before the offending call, there is a line that assigns the UsnJournalID into the read data structure.
For Windows 10, though, the other two members of the V1 structure are not initialized. I initialized them right after the UsnJournalID's initialization with:
#if (NTDDI_VERSION >= NTDDI_WIN8)
ReadData.MinMajorVersion = JournalData.MinSupportedMajorVersion;
ReadData.MaxMajorVersion = JournalData.MaxSupportedMajorVersion;
#endif
When I ran my code after doing this, it worked correctly without the error code. I remember reading in the Volume Management API discussion that the Min and Max versions needed to be set. I forgot exactly where, because I've been reading and testing this stuff for a couple days.
Anyway, I hope that clarifies the issue for anyone coming after me.
Replace the READ_USN_JOURNAL_DATA structure with READ_USN_JOURNAL_DATA_V0 data structure and initialize it.
This worked for me
READ_USN_JOURNAL_DATA_V0 ReadData;
ZeroMemory(&ReadData, sizeof(ReadData));
ReadData.ReasonMask = 0xFFFFFFFF;

Injected DLL not writing file

I am writing C code, using WinAPI, that installs a global hook (WH_GETMESSAGE) which injects a DLL into all compatible processes in the system. The injected DLL monitors a certain messages passed to the message queue and creates a text file. The callback function in the DLL should create a text file using a randomly generated name in a specific directory. The methods are working when tested on main but fail when in the DLL (i.e no text file is created). NB: The following are working fine.
The DLL is successfully injected into all (32bit) processes, checked using
ProcessExplorer.
The Callback function is being called, checked using
MessageBeep(-1)
Is there something I am missing in the code? and are there any ways to debug my DLL code injected in a processes e.g in Firefox.
Here's my code in the DLL:
LRESULT CALLBACK GetMsgProc(int code,WPARAM wParam,LPARAM lParam){
if (code < 0) {
return CallNextHookEx(NULL, code, wParam, lParam);
}
if ((code == HC_ACTION) && (wParam == PM_REMOVE)){
//for any message create and write to text file
writeToLogFile();
}
return CallNextHookEx(NULL, code, wParam, lParam);
}
Here's the code that creates the text file:
BOOL writeToLogFile() {
char fileName[10];
char fName[] = "C:\\Users\\MyDir\\";
char buffer[75]; //place concatenated string here
generateRandomStr(fileName); //methos to generate file name
snprintf(buffer, sizeof(buffer), "%s%s.txt", fName, fileName);
HANDLE fHandle =
CreateFile(buffer,
FILE_GENERIC_READ | FILE_GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL);
//file handle code check ommited for brevity
DWORD bytesWritten;
WriteFile(fHandle, buffer, strlen(buffer), &bytesWritten, NULL);
CloseHandle(fHandle);
return TRUE;
}
/*Generate file name string (a-z characters)*/
VOID generateRandomStr(char holder[]) {
size_t i = 0;
srand(time(NULL)); //system clock seconds for seed
while (i < 9) {
int x = (97 + rand() % 97);
if (x > 96 && x < 122) {
holder[i] = ((char)x);
//puts((char)x);
i++;
}
}
holder[i++] = '\0'; //terminate the string
Check out the following http://www.codeproject.com/Articles/116253/Hot-Patching-Made-Easy. It talks about DLL injection.
Thanks everyone for the comments and tips. Finally managed to make it work, the issue was with the function CreateFile which was failing (some illegal characters in the file name generated). After using the OutputDebugString, I was able to view the output and debugged the generateRandomStr function responsible for generating the filename and it worked.

force any running process to crash

I would like to crash a running program of my choice (e.g., notepad++, becrypt, word) for software testing purposes.
I know how to BSOD, I know how to cause a program I write to crash, I know how to end process - but how to crash an existing process I do not!
any help?
Well, use CreateRemoteThread on a remote process and invoke something [1] that crashes the process reliably. I'm not sure whether CreateRemoteThread guards against null pointers, but you could pass an address in the null page to it and have the remote process execute that.
[1] null pointer or null page access, division by zero, invoking a privileged instruction, int3 ...
Example:
#include <stdio.h>
#include <tchar.h>
#include <Windows.h>
BOOL setCurrentPrivilege(BOOL bEnable, LPCTSTR lpszPrivilege)
{
HANDLE hToken = 0;
if(::OpenThreadToken(::GetCurrentThread(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, FALSE, &hToken)
|| ::OpenProcessToken(::GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
{
TOKEN_PRIVILEGES tp;
LUID luid;
if(!::LookupPrivilegeValue(
NULL, // lookup privilege on local system
lpszPrivilege, // privilege to lookup
&luid ) ) // receives LUID of privilege
{
::CloseHandle(hToken);
return FALSE;
}
tp.PrivilegeCount = 1;
tp.Privileges[0].Luid = luid;
tp.Privileges[0].Attributes = (bEnable) ? SE_PRIVILEGE_ENABLED : 0;
// Enable the privilege or disable all privileges.
if(!::AdjustTokenPrivileges(
hToken,
FALSE,
&tp,
sizeof(TOKEN_PRIVILEGES),
(PTOKEN_PRIVILEGES) NULL,
(PDWORD) NULL)
)
{
CloseHandle(hToken);
return FALSE;
}
::CloseHandle(hToken);
}
return TRUE;
}
int killProcess(DWORD processID)
{
HANDLE hProcess = ::OpenProcess(PROCESS_ALL_ACCESS, FALSE, processID);
if(hProcess)
{
if(!setCurrentPrivilege(TRUE, SE_DEBUG_NAME))
{
_tprintf(TEXT("Could not enable debug privilege\n"));
}
HANDLE hThread = ::CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)1, NULL, 0, NULL);
if(hThread)
{
::CloseHandle(hThread);
}
else
{
_tprintf(TEXT("Error: %d\n"), GetLastError());
::CloseHandle(hProcess);
return 1;
}
::CloseHandle(hProcess);
}
return 0;
}
int __cdecl _tmain(int argc, _TCHAR *argv[])
{
killProcess(3016);
}
Of course you'll want to adjust the PID in the call to killProcess. Compiled with WNET DDK and tested on 2003 Server R2.
The gist here is that we tell the remote process to execute code at address 0x1 ((LPTHREAD_START_ROUTINE)1), which is inside the null page but not a null pointer (in case there are checks against that). The crud around the function, in particular setCurrentPrivilege is used to gain full debug privileges so we can do our evil deed.
You can use DLL injection technique in order to inject your code into another process. Then in your injected code do something simple like abort() or division by zero.
A two steps mechanism is needed:
inject the process to crash (using an injection library, using Detours, using a Hook installation, etc..). What you choose depends on the time and knowledge you have and other preconditions (like credentials, anti-injection protection, size of the foot-print you want to leave..)
perform an invalid operation in the injected process (like int 2Eh, divide by null, etc..)
Here's how to do that with the winapiexec tool:
winapiexec64.exe CreateRemoteThread ( OpenProcess 0x1F0FFF 0 1234 ) 0 0 0xDEAD 0 0 0
Replace 1234 with the process id and run the command, the process will crash.

Can't add my application to autostart

I writing small application in pure C++. But now I encourage strange problem. I wanted to add my application to autostart but it not working. I use this code to access to Registry:
BOOL SetKeyData(HKEY hRootKey, WCHAR *subKey, DWORD dwType, WCHAR *value, LPBYTE data, DWORD cbData)
{
HKEY hKey;
if(RegCreateKeyW(hRootKey, subKey, &hKey) != ERROR_SUCCESS)
return FALSE;
LSTATUS status = RegSetValueExW(hKey, value, 0, dwType, data, cbData);
if(status != ERROR_SUCCESS)
{
RegCloseKey(hKey);
return FALSE;
}
RegCloseKey(hKey);
return TRUE;
}
At first I thought that problem is in data that I serve, so i converted WCHAR with path to LPBYTE like this and execute this function in this way:
size_t i;
char *pMBBuffer = (char *)malloc( MAX_PATH );
wcstombs_s(&i, pMBBuffer, MAX_PATH, my_program, MAX_PATH-1 );
SetKeyData(HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows\\CurrentVersion\\Run", REG_SZ, L"zwApplication", (LPBYTE)pMBBuffer, i))
I get status code ERROR_ACCESS_DENIED. Maybe problem is policy in Windows 7, but I thought that I have full access to everything in HKEY_LOCAL_MACHINE. How to solve this problem?
Writing to HKEY_LOCAL_MACHINE requires that your app runs with elevated privileges. Which means your app would require to set this in its manifest file.
Without this, you can only write to HKEY_CURRENT_USER, or read from HKEY_LOCAL_MACHINE - but for your autostart requirement, that would work just as fine.

CreateRemoteThread returning ERROR_ACCESS_DENIED - Windows 7 DLL Injection

I'm trying to write a program that uses CreateRemoteThread to inject a dll.
The problem is that CreateRemoteThread is refusing to work. GetLastError() is returning 5 which is ERROR_ACCESS_DENIED. I cant figure why!
I am working from this video http://www.youtube.com/watch?v=H3O3hmXkt1I .
#include <iostream>
#include <direct.h>
#include <Windows.h>
#include <TlHelp32.h>
using namespace std;
char* GetCurrentDir()
{
char* szRet = (char*)malloc(MAX_PATH);
_getcwd(szRet, MAX_PATH);
return szRet;
}
LPCTSTR SzToLPCTSTR(char* szString)
{
LPTSTR lpszRet;
size_t size = strlen(szString)+1;
lpszRet = (LPTSTR)malloc(MAX_PATH);
mbstowcs_s(NULL, lpszRet, size, szString, _TRUNCATE);
return lpszRet;
}
void WaitForProcessToAppear(LPCTSTR lpcszProc, DWORD dwDelay)
{
HANDLE hSnap;
PROCESSENTRY32 peProc;
BOOL bAppeared = FALSE;
while(!bAppeared)
{
if((hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0)) != INVALID_HANDLE_VALUE)
{
peProc.dwSize = sizeof(PROCESSENTRY32);
if(Process32First(hSnap, &peProc))
while(Process32Next(hSnap, &peProc) && !bAppeared)
if(!lstrcmp(lpcszProc, peProc.szExeFile))
bAppeared = TRUE;
}
CloseHandle(hSnap);
Sleep(dwDelay);
}
}
DWORD GetProcessIdByName(LPCTSTR lpcszProc)
{
HANDLE hSnap;
PROCESSENTRY32 peProc;
DWORD dwRet = -1;
if((hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0)) != INVALID_HANDLE_VALUE)
{
peProc.dwSize = sizeof(PROCESSENTRY32);
if(Process32First(hSnap, &peProc))
while(Process32Next(hSnap, &peProc))
if(!lstrcmp(lpcszProc, peProc.szExeFile))
dwRet = peProc.th32ProcessID;
}
CloseHandle(hSnap);
return dwRet;
}
BOOL InjectDll(DWORD dwPid, char* szDllPath)
{
DWORD dwMemSize;
HANDLE hProc;
LPVOID lpRemoteMem, lpLoadLibrary;
BOOL bRet = FALSE;
if((hProc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPid)) != NULL)
{
dwMemSize = strlen(szDllPath);
if((lpRemoteMem = VirtualAllocEx(hProc, NULL, dwMemSize, MEM_COMMIT, PAGE_READWRITE)) != NULL)
if(WriteProcessMemory(hProc, lpRemoteMem, szDllPath, dwMemSize, NULL))
{
lpLoadLibrary = GetProcAddress(GetModuleHandleA("kernel32.dll"), "LoadLibraryA");
if(CreateRemoteThread(hProc, NULL, 0, (LPTHREAD_START_ROUTINE)lpLoadLibrary, lpRemoteMem, 0, NULL) != NULL)
{
bRet = TRUE;
}
cout << GetLastError();
}
}
CloseHandle(hProc);
return bRet;
}
int main()
{
char szProc[MAX_PATH], szDll[MAX_PATH];
char* szDllPath = (char*)malloc(MAX_PATH);
LPTSTR lpszProc = NULL;
for(;;)
{
cout << "Process: ";
cin >> szProc;
cout << "DLL: ";
cin >> szDll;
szDllPath = GetCurrentDir();
strcat_s(szDllPath, MAX_PATH, "\\");
strcat_s(szDllPath, MAX_PATH, szDll);
cout << "Waiting for process.. ." << szDllPath << " " << szDll << endl;
WaitForProcessToAppear(SzToLPCTSTR(szProc), 100);
if(InjectDll(GetProcessIdByName(SzToLPCTSTR(szProc)), szDllPath))
cout << "Injection Succeeded!" << endl;
else
cout << "Injection Failed!" << endl;
cout << "\n";
}
return 0;
After a fair amount of googling I cant find a reason why this should not be working.
Does CreateRemoteThread not work under Windows 7 ?
If it does, have I made any obvious mistakes ?
The reason it fails is because your code is 32-bit and your target process is 64-bit.
It doesn't matter how many privileges you own. Windows won't let that happen.
I had the same problem. Either you spawn a system 32-bit exe and inject that or port your code to 64-bit (which means it won't work on 32-bit systems).
EDIT
A long time ago, I found a nice way of injecting code into and from any processor mode-target. It involves dynamically switching the processor mode to that of (any)the target. Dubbed "heaven's gate". To do this you have to use inline assembly. So basically, you can have both 64-bit and 32-bit code in a 32-bit exe, detect if the machine is 64-bit, then jump into 64-bit mode and run the 64-bit code. You'd then walk the imports to find ntdll and load 64-bit kernel.dll and other libraries.
Link: https://www.google.com/search?q=heaven's+gate+windows
Immediate problems I see are that you are not getting the access token which should be done as so:
HANDLE hToken;
TOKEN_PRIVILEGES tp;
HANDLE hProcess = OpenProcess( PROCESS_ALL_ACCESS, FALSE, GetCurrentProcessId() );
tp.PrivilegeCount = 1;
LookupPrivilegeValue( NULL, _T("SeDebugPrivilege"), &tp.Privileges[0].Luid );
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
OpenProcessToken( hProcess, TOKEN_ADJUST_PRIVILEGES, &hToken );
AdjustTokenPrivileges( hToken, FALSE, &tp, NULL, NULL, NULL );
CloseHandle( hToken );
I don't have time to look through all your code right now, but here is something I ripped out of one of my previous projects:
// returns open process handle
HANDLE InjectDLL( DWORD dwPID, LPCWSTR szDLLPath, HMODULE* lphInjected ) {
int cszDLL;
LPVOID lpAddress;
HMODULE hMod;
HANDLE hThread;
HANDLE hProcess = OpenProcess( PROCESS_CREATE_THREAD |
PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION |
PROCESS_VM_WRITE | PROCESS_VM_READ, FALSE, dwPID );
if( hProcess == NULL ) {
return NULL;
}
cszDLL = ( wcslen( szDLLPath ) + 1 ) * sizeof( WCHAR );
// Injection
lpAddress = VirtualAllocEx( hProcess, NULL, cszDLL, MEM_COMMIT, PAGE_EXECUTE_READWRITE );
if( lpAddress == NULL ) {
return NULL;
}
WriteProcessMemory( hProcess, lpAddress, szDLLPath, cszDLL, NULL );
hMod = GetModuleHandle( L"kernel32.dll" );
if( hMod == NULL ) {
return NULL;
}
hThread = CreateRemoteThread( hProcess, NULL, 0,
(LPTHREAD_START_ROUTINE)( GetProcAddress( hMod,
"LoadLibraryW" ) ), lpAddress, 0, NULL );
// Locate address our payload was loaded
if( hThread != 0 ) {
WaitForSingleObject( hThread, INFINITE );
GetExitCodeThread( hThread, ( LPDWORD )lphInjected );
VirtualFreeEx( hProcess, lpAddress, 0, MEM_RELEASE );
CloseHandle( hThread );
}
return hThread != 0 ? hProcess : NULL;
}
See if it helps. Will look again later.
OK, your code is likely to fail in windows 7 and Vista because of "Protected processes", that is, processes which only can be manipulated by other Protected Processes, like explorer.exe, etc... In Windows 7 x32 there is a way: since you are able to load unsigned drivers,... well, you are done (search for Alex Ionescu in google). In Windows 7 x64, though, you can't (duh!)
"The fourth parameter of the CreateRemoteThread() is an address. In your case it is the LoadLibraryA address. However, in windows 7, Kernel32.dll/LoadLibraryA base address will various in different process;"
Well, that's not remotely true, because DLLs are shared at the same addresses in every process, despite ASLR. DLLs can be rebased, though, but you can call GetProcAddress before calling CreateRemoteThread, so it is very unlikely that the DLL will get rebased meanwhile.
I think CreateRemoteThread() dll injection method can not work in windows 7.
The fourth parameter of the CreateRemoteThread() is an address. In your case it is the LoadLibraryA address. However, in windows 7, Kernel32.dll/LoadLibraryA base address will various in different process; Therefore, the CreateRemoteThread() will not work since the address is not what u expected. This is my own opinion, hope it will help. :)
CreateRemoteThread function does not work in Win Vista/7. You have to use NTCreateThread function,which is undocumented, for that.
TLDR : your code is okey , change the Visual Studio debug/compile target to x64.
I've faced the same problem before, your code is Okey, The problem is , the Visual Studio(or any sane person) execute its programs in x86 mode (32bit) by default, because it would be nice to compile your program in a way that runs in both x86 or x64 architecture but not in the process injection scenario! because of its system calls.
In the code injection case, you should change the build and debug setting of the VS to compile/debug for x64 processor in properties of your project in the project explorer,
or if you cross compiling your program, you should use x64 compiler.
If you are looking for global process injection method, there was a method called Heaven’s Gate or The 0x33 Segment Selector, which was used in Vawtrak banking malware.
You could see this link about Heaven’s Gate method, which says:
In other words, it gives one the ability to create “naked” 64-bit
code, which will be able to run covertly, including issuing system
calls, without the majority of products able to intercept and/or
introspect its execution

Resources