Introduction
In my previous article, I released code for injecting into running explorer.exe on 32 bit platform which uses 32 bit instructions as shell code which were injected in the process.
Here, we will see a generic code which does not involve any shell code or assembly instructions that are hard coded in the injector, whereas it transfers this responsibility to compiler to prepare the proper assembly for 32 bit and 64 bit version.
Refer to my previous tip Code Injection.
Code
#include <windows.h>
#include <fstream>
#include <stdlib.h>
#pragma comment(lib,"advapi32.lib")
#pragma comment(lib,"user32.lib")
typedef BOOL (WINAPI* CreatePrcssParam)(LPCTSTR, LPTSTR, LPSECURITY_ATTRIBUTES,
LPSECURITY_ATTRIBUTES, BOOL, DWORD, LPVOID, LPCTSTR, LPVOID, LPVOID);
struct PARAMETERS{
LPVOID CreateProcessInj;
char lpApplicationName[50];
char lpCommandLine[10];
LPSECURITY_ATTRIBUTES lpProcessAttributes;
LPSECURITY_ATTRIBUTES lpThreadAttributes;
BOOL bInheritHandles;
DWORD dwCreationFlags;
LPVOID lpEnvironment;
LPCTSTR lpCurrentDirectory;
LPVOID lpStartupInfo;
LPVOID lpProcessInformation;
};
int privileges();
DWORD myFunc(PARAMETERS * myparam);
DWORD Useless();
int main()
{
privileges();
_STARTUPINFOA si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
ZeroMemory(&pi, sizeof(pi));
DWORD pid;
GetWindowThreadProcessId(FindWindow(NULL, L"Start Menu"), &pid);
HANDLE p;
p = OpenProcess(PROCESS_ALL_ACCESS, false, pid);
if (p == NULL)
{
printf("ERROR");
return 1; }
char * AppName = "C:\\Windows\\notepad.exe";
char * CmdLine = "";
LPVOID StrtUpInfo = VirtualAllocEx(p, NULL, sizeof(si), MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
WriteProcessMemory(p, StrtUpInfo, &si, sizeof(si), NULL);
LPVOID PrcssInfo = VirtualAllocEx(p, NULL, sizeof(si), MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
WriteProcessMemory(p, PrcssInfo, &pi, sizeof(pi), NULL);
PARAMETERS data = {0};
HMODULE Kernel32 = LoadLibrary(L"Kernel32.dll");
data.CreateProcessInj = GetProcAddress(Kernel32, "CreateProcessA");
strcpy_s(data.lpApplicationName,AppName);
strcpy_s(data.lpCommandLine, CmdLine);
data.lpProcessAttributes = NULL;
data.lpThreadAttributes = NULL;
data.bInheritHandles = FALSE;
data.dwCreationFlags = NULL;
data.lpEnvironment = NULL;
data.lpCurrentDirectory = NULL;
data.lpStartupInfo = StrtUpInfo;
data.lpProcessInformation = PrcssInfo;
DWORD size_myFunc = (PBYTE)Useless - (PBYTE)myFunc;
LPVOID MyFuncAddress = VirtualAllocEx(p, NULL, size_myFunc, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
WriteProcessMemory(p, MyFuncAddress, (void*)myFunc, size_myFunc, NULL);
LPVOID DataAddress = VirtualAllocEx(p, NULL, sizeof(PARAMETERS), MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
WriteProcessMemory(p, DataAddress, &data, sizeof(PARAMETERS), NULL);
HANDLE thread = CreateRemoteThread(p, NULL, 0, (LPTHREAD_START_ROUTINE)MyFuncAddress, DataAddress, 0, NULL);
if (thread != 0){
WaitForSingleObject(thread, INFINITE); VirtualFree(MyFuncAddress, 0, MEM_RELEASE); VirtualFree(DataAddress, 0, MEM_RELEASE); CloseHandle(thread);
CloseHandle(p); }
else{
printf("Error!");
}
return EXIT_SUCCESS;
}
static DWORD myFunc(PARAMETERS * myparam){
CreatePrcssParam CreatePrcss = (CreatePrcssParam)myparam->CreateProcessInj;
BOOL result = CreatePrcss((LPCTSTR)myparam->lpApplicationName, NULL,
myparam->lpProcessAttributes, myparam->lpThreadAttributes,
myparam->bInheritHandles, myparam->dwCreationFlags, myparam->lpEnvironment,
myparam->lpCurrentDirectory, myparam->lpStartupInfo, myparam->lpProcessInformation);
return 0;
}
static DWORD Useless(){
return 0;
}
int privileges(){
HANDLE Token;
TOKEN_PRIVILEGES tp;
if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &Token))
{
LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &tp.Privileges[0].Luid);
tp.PrivilegeCount = 1;
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
if (AdjustTokenPrivileges(Token, 0, &tp, sizeof(tp), NULL, NULL) == 0){
return 1; }
else{
return 0; }
}
return 1;
}
What you have to do is just compile this code in 32 bit mode if you want a 32 bit injector or in 64 bit mode if you need a 64 bit injector.
This code forces the arguments of CreateProcess
function to be stack based and these parameters are passed using the lpParameter
field of CreateRemoteThread
function so there will be no unresolved addresses of parameters when the injection part is ported to a foreign process.
Other information on how to prevent code injection is explained in my previous tip.