DLL injection Written by Darawk 편역 : poc@securityproof.net * 이글은 Codebreakers Journal Vol.1, No.1, 2007 에서발표된것이며, 오역이나 오타가있을수있으니원문을참고시기바랍니다.
이문서에서, 나는프로세스에 dll을삽입하는알려진 ( 적어도내가아는한에서 ) 방법들모두를다룰것이다. Dll injection은 game hacking, function hooking, code patching, keygenning, unpacking 등에서굉장히유용하게사용될수있다. 이기술에대해서웹상에여러문서들이있지만, 나는아직기술을세부적으로기술하면서각각에대해장점과단점을설명한완벽한튜토리얼은보지못했다 ( 물론내가알고있는것보다더많은것이 있을수있다 ). 이것들이이문서에서당신들에게알려주고자하는것들이다. 적당한 credit 이주어지고알림없이수정만하지않는다면, 이문서의이용은자유다. The CreateRemoteThread method 이기술을난많이사용해왔지만, 최근에들어많은사람들이이것을본적이없거나사용하는방법을모른다는것을알게되었다. 하지만, 이것에대해서난 credit을가질수는없다. 이것을 codeproject의기사에서얻었기때문이다. 어쨌든이것은많은사람들이사용하는법을알아야만하는휼륭한기술이다. 이기술은간단하고우아하다. Windows API에는CreateRemoteThread() 라는함수가있다. 이것을이용해우리는다른프로세스에서쓰레드를시작할수있다. 여기서, 난당신이쓰레드의동작에관해알고, CreateThread같은함수를사용할수있다고가정하겠다. 이방법의주요단점은 windows NT이상에서만사용할수있다는것이다. 크래쉬를막기위해당신은시스템이 NT 기반인지다음함수를사용해시스템이 NT 기반인지알아보아야한다.( 이점을지적해준 CatID 에게감사한다 ): bool IsWindowsNT()
// check current version of Windows DWORD version = GetVersion(); // parse return DWORD majorversion = (DWORD)(LOBYTE(LOWORD(version))); DWORD minorversion = (DWORD)(HIBYTE(LOWORD(version))); return (version < 0x80000000); CreateRemoteThread 의 MSDN 정의는다음과같다.: HANDLE CreateRemoteThread( HANDLE hprocess, LPSECURITY_ATTRIBUTES lpthreadattributes, SIZE_T dwstacksize, LPTHREAD_START_ROUTINE lpstartaddress, LPVOID lpparameter, DWORD dwcreationflags, LPDWORD lpthreadid ); 이것은본질적으로 hprocess인자 1 를갖는 CreateThread이므로우린새로운스레드가어떤프로세스내에서만들어지는지구분할수있다. 이제우린우리가접촉한프로세스의내부함수에서스레드를시작하길원한다. 그러나 dll을삽입하기위해선조금다른어떤것을해야만한다. 1 hprocess: 스레드가생성될타깃프로세스. 스레드생성에성공하기위해서는이핸들에대해적당한권한이있어야한다.
BOOL InjectDLL(DWORD ProcessID) HANDLE Proc; char buf[50]=0; LPVOID RemoteString, LoadLibAddy; if(!processid) return false; Proc = OpenProcess(CREATE_THREAD_ACCESS, FALSE, ProcessID); if(!proc) sprintf(buf, "OpenProcess() failed: %d", GetLastError()); MessageBox(NULL, buf, "Loader", NULL); return false; LoadLibAddy = (LPVOID)GetProcAddress(GetModuleHandle("kernel32.dll"), "LoadLibraryA"); RemoteString = (LPVOID)VirtualAllocEx(Proc, NULL, strlen(dll_name), MEM_RESERVE MEM_COMMIT, PAGE_READWRITE); WriteProcessMemory(Proc, (LPVOID)RemoteString, DLL_NAME,strlen(DLL_NAME), NULL); CreateRemoteThread(Proc, NULL, NULL, (LPTHREAD_START_ROUTINE)LoadLibAddy, (LPVOID)RemoteString, NULL, NULL);
CloseHandle(Proc); return true; 이코드는 LoadLibrary() 의 lpstaraddress와함께 CreateRemoteThread() 를호출한다. 그래서리모트프로세스에서새로운스레드를시작하고 LoadLibrary() 를실행한다. 운좋게도, 이함수는단하나의인자 ( 로드할 dll의이름 ) 만을갖는다. 우리는 CreateRemoteThread() 의인자값필드에서이것을건네줄수있다. 그러나작은문제가있다. 이스레드가우리의주소공간에서실행되는지않을것이기에, 우리의주소공간에있는문자열 (dll의이름같은 ) 을참조할수없다. 그래서 CreateRemoteThread() 를호출하기전에우리는 VirtualAllocEx() 를이용하여다른프로세스에공간을할당하고거기에우리의문자열을써야만한다. 마지막으로, CreateRemoteThread() 의하나의인자값필드에서리모트프로세스내부에 문자열로의포인터를건네줄수있다. 자보라... 우리의 dll 은이제로드되었고리모트프로세스안에서부드럽게돌아가고있다. 이것이 dll 을로드할필요가있을때마다사용하는로더프로그램이다. The SetWindowsHookEx method SetWindowsHookEx 기법은앞의것보다좀더침입적이고삽입된프로세스에서우리가원치않는문제를일으킨다. 그러나사용하기쉽고그것만의장점이있다.( 한번에시스템의모든프로세스의삽입할수있는것같은 ). SetWindowsHookEx() 함수는주어진스레드에대해당신이윈도우메시지를 hook 할수있도록설계되었다. 이것은당신이프로세스주소공간에 dll을삽입하는것을필요로한다. 그래서 SetWindowsHookEx() 는우리를
위해그것모두를다룬다. Dll 은 hook 을위해그것이만든함수를가져야만하며, 그렇지 않으면 crash 할것이다. HHOOK SetWindowsHookEx( int idhook, HOOKPROC lpfn, HINSTANCE hmod, DWORD dwthreadid ); idhook은우리가 hook하기원하는메시지의 ID이다. 많은것들이있다. 그러나우린가능한침입적이지않고 AV 소프트웨어 (SetWindowsHookEx는 ring3 키로거들의주요소이다 ) 에서경고가가능한나지않도록하는것을사용할것이다. WH_CBT는충분히해가없는것으로보인다. Quote: WH_CBT 컴퓨터기반교육 (CBT) 어플리케이션에유용한공고를받는 hook 프로시저를 설치하라. 자세한정보는 CBTProc hook 프로시저를보라. --MSDN 그래서우린우리의 dll 에플라시보 (placebo) 2 CBT hook proc 를만들어야 hook 이 호출되었을때, 우린그것을적절하게다룰수있다. 2 가짜의의미로해석될듯.
LRESULT CALLBACK CBTProc(int ncode, WPARAM wparam, LPARAM lparam) return CallNextHookEx(0, ncode, wparam, lparam); ; 우리가하고있는것은이메시지를위해존재하는 hook들의사슬에서다음훅을호출하는것이다. SetWindowsHookEx() 로돌아가서우린다음인자인 lpfn을볼수있다. Lpfn은 long pointer to function 이다. 그것은우리의 CBT hook proc함수로의포인터이다. 그래서이것을얻기위해우린그주소를하드코딩하던지우선 dll을로딩해야한다. 어떤것을하드코드하는것은좋지않은생각이므로우린함수의주소를얻기위해 LoadLibrary() 와 GetProcAddress() 를사용하여 dll을로드할것이다. HMODULE hdll; unsigned long cbtprocaddr; hdll = LoadLibrary("injected.dll"); cbtprocaddr = GetProcAddress(hDll, "CBTProc"); 이제우리는우리의함수주소를 cbtprocaddr 안에갖게되었다. 우리의 dll 을다루는 SetWindowsHookEx() 의세번째파라미터는 CBTProc 의주소를얻는과정에서이미 얻었다 (hdll 은 LoadLibrary 에의해리턴된우리의 dll 에대한핸들이다 ). 이제 SetWindowsHookEx() 함수에서 dwthreadid 파라미터하나만남았다. 만약당신이 당신의 dll 을시스템의모든프로세스에삽입 ( 전역함수 hook, 키로거, 트로얀, 루트킷등에
유용 ) 하길원한다면간단하게이파라미터에 0을넣을수있다. 만약당신이특정프로세스를타깃으로하길원한다면, 당신은그것의스레드중하나의 ID를얻어야만한다. 이것을하기위해많은방법이있고나는 Appendix B에서내가생각할수있는만큼나열해볼것이다. 그래서그것을우리의작은함수안에함께넣을것이다 : BOOL InjectDll(char *dllname) HMODULE hdll; unsigned long cbtprocaddr; hdll = LoadLibrary(dllName); cbtprocaddr = GetProcAddress(hDll, "CBTProc"); SetWindowsHookEx(WH_CBT, cbtprocaddr, hdll, GetTargetThreadIdFromWindow("targetApp")); return TRUE; The code cave method 프로세스가우리의 Dll 을로드하도록강제하기위해 windows API 함수를공략하는대신에, 이번에우리는타깃어플리케이션내부에조그만청크메모리를할당하고우리의 Dll 을
로드하는작은스텁 (stub) 3 를삽입할것이다. 이접근방법의장점은윈도우의어떤 버전에서든지동작할수있고, 언급된방법들중가장탐지되기어렵다. 우리의 스텁 (stub) 는이렇다. declspec(naked) loaddll(void) _asm // Placeholder for the return address push 0xDEADBEEF // Save the flags and registers pushfd pushad // Placeholder for the string address and LoadLibrary push 0xDEADBEEF mov eax, 0xDEADBEEF // Call LoadLibrary with the string parameter call eax // Restore the registers and flags popad popfd // Return control to the hijacked thread 3 stub: 상위프로그램이호출했을때완벽한기능을임시로흉내내는가짜모듈
ret 0xDEADBEEF 는우리가미리알수없는주소를표시하기위해두었고, 실행중에 수정해야한다. 자, 이제이작업을하기위해우리가해야할것들을나열해보자 : - 스텁 (stub) 를위한공간할당 - dll 의이름을위한공간할당 - 타깃의메인스레드를중지한다. - 실행되어질다음명령의주소를얻는다 ( 다음단계를위해필요하다 ) - 스텁 (stub) 내에돌아가기위한적당한주소로패치한다. - dll 이름의주소를패치한다 - LoadLibrary 의주소를패치한다. - 우리의스텁의시작주소에타깃의스레드에서실행되어질다음명령의주소를설정한다. - 타깃스레드를다시시작한다. 타깃내에공간을할당하기위해, 우리는 VirtualAllocEx() 를사용할것이다. 우리는이것을위해 VM_OPERATION권한으로프로세스핸들을여는것이필요하다. 우리의 dll이름문자열을위해우리는단지읽기와쓰기권한만필요하다. 그러나스텁을위해서는우리는읽기, 쓰기, 실행권한이필요하다. 그러면우린우리의 dll이름문자열을쓸것이고, 삽입된스텁으로부터그것을참조할수있다.
void *dllstring, *stub; unsigned long wowid; HANDLE hprocess //See Appendix A for //this function wowid = GetTargetProcessIdFromProcname(PROC_NAME); hprocess = OpenProcess((PROCESS_VM_WRITE PROCESS_VM_OPERATION), false, wowid); dllstring = VirtualAllocEx(hProcess, NULL, (strlen(dll_name) + 1), MEM_COMMIT, PAGE_READWRITE); stub = VirtualAllocEx(hProcess, NULL, stublen, MEM_COMMIT, PAGE_EXECUTE_READWRITE); WriteProcessMemory(hProcess, dllstring, DLL_NAME, strlen(dll_name), NULL); 우리의다음일들을위하여, 우린타깃스레드중하나에대한핸들이필요할것이다. 우린스레드의 ID를얻기위해 Appendix B의함수들을사용할수있고, 그런후핸들을얻기위한 OpenThread API를사용할수있다. 우린컨텍스트 (context) 를얻고설정할수있어야하고, 또한스레드를중지하거나재시작할수있어야한다. unsigned long threadid; HANDLE hthread;
threadid = GetTargetThreadIdFromProcname(PROC_NAME); hthread = OpenThread((THREAD_GET_CONTEXT THREAD_SET_CONTEXT THREAD_SUSPEND_RESUME), false, threadid); 이제는 컨텍스트 (context) 를얻기위해스레드를멈추어야한다. 스레드의컨텍스트는주변장치정보는물론모든레지스터들의현재상태이다. 그러나우린주로실행되어질다음명령을가리키는 EIP레지스터에관심이있다. 그래서만약우리가컨텍스트정보를받기전스레드를중지시키지않는다면, 그것은계속실행될것이고우리가정보를얻을때그것은유효하지않게된다. 일단스레드를중지시키면우린 GetThreadContext() 함수를이용해서컨텍스트를받을것이다. 우린실행될다음명령값을얻어서우린우리의스텁이돌아가야하는곳을알수있다. 그런후에는단지적당한포인터를갖도록스텁을패칭하고그것이실행되도록스레드가그것을실행하도록강제하는것이문제이다 : SuspendThread(hThread); ctx.contextflags = CONTEXT_CONTROL; GetThreadContext(hThread, &ctx); oldip = ctx.eip; //Set the EIP of the context to the address of our stub ctx.eip = (DWORD)stub; ctx.contextflags = CONTEXT_CONTROL; //Right now loaddll is code, which isn't writable. We need //to change that.
VirtualProtect(loadDll, stublen, PAGE_EXECUTE_READWRITE, &oldprot); //Patch the first push instruction memcpy((void *)((unsigned long)loaddll + 1), &oldip, 4); //Patch the 2nd push instruction memcpy((void *)((unsigned long)loaddll + 8), &dllstring, 4); //Patch the mov eax, 0xDEADBEEF to mov eax, LoadLibrary memcpy((void *)((unsigned long)loaddll + 13), &loadlibaddy, 4); WriteProcessMemory(hProcess, stub, loaddll, stublen, NULL); //Write the stub into the target //Set the new context of the target's thread SetThreadContext(hThread, &ctx); //Let the target thread continue execution, starting at our stub ResumeThread(hThread); 이제남은것은증거를없애는것이다. 우리가그것하기전타깃이우리의스텁을확실히 실행하도록우린잠시동안인젝터를멈추어야만한다. 우린우리가할당한메모리가 언매핑되고인젝터를나가기전에 8 초동안멈추기위해 Sleep() 를사용할것이다. Sleep(8000); VirtualFreeEx(hProcess, dllstring, strlen(dll_name), MEM_DECOMMIT); VirtualFreeEx(hProcess, stub, stublen, MEM_DECOMMIT); CloseHandle(hProcess); CloseHandle(hThread);
이방법은윈도우의어떤버전에서든동작할것이고, A/V 알람이나프로그램이기능불량을 일으키게할가능성이가장적을것이다. 만약우리가그것을이해하고적당히실현할수 있다면, 이것은세가지방법중최고가될것이다. Appendix A - Methods of obtaining a process ID 만약당신이타깃으로삼은프로세스가윈도우를가지고있다면, 당신은아래보이는것 처럼 GetWindowTheadPocessId 와함께 FindWindow 함수를사용할수있다 : unsigned long GetTargetProcessIdFromWindow(char *classname, char *windowname) unsigned long procid; HWND targetwnd; targetwnd = FindWindow(className, windowname); GetWindowThreadProcessId(targetWnd, &procid); return procid; 만약당신이실행파일의이름만을알거나그것이윈도우를지니고있지않다면 :
unsigned long GetTargetProcessIdFromProcname(char *procname) PROCESSENTRY32 pe; HANDLE thsnapshot; BOOL retval, ProcFound = false; thsnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); if(thsnapshot == INVALID_HANDLE_VALUE) MessageBox(NULL, "Error: unable to create toolhelp snapshot", "Loader", NULL); return false; pe.dwsize = sizeof(processentry32); retval = Process32First(thSnapshot, &pe); while(retval) if(strstri(pe.szexefile, procname) ) ProcFound = true; break; retval = Process32Next(thSnapshot,&pe);
pe.dwsize = sizeof(processentry32); return pe.th32processid; Appendix B - Methods of obtaining a thread ID 만약당신이타깃으로정한프로세스가윈도우를지니고있다면, 당신은아래보이는 것처럼 GetWindowThreadProcessId 와 toolhelp API 와함께 FindWindow 함수를사용할 수있다. unsigned long GetTargetThreadIdFromWindow(char *classname, char *windowname) HWND targetwnd; HANDLE hprocess unsigned long processid, ptid, threadid; targetwnd = FindWindow(className, windowname); GetWindowThreadProcessId(targetWnd, &processid); _asm
mov eax, fs:[0x18] add eax, 36 mov [ptid], eax hprocess = OpenProcess(PROCESS_VM_READ, false, processid); ReadProcessMemory(hProcess, (const void *)ptid, &threadid, 4, NULL); CloseHandle(hProcess); return threadid; 만약당신이타깃의실행파일이름만을안다면, 당신은그것의장소를찾기위해이코드를 사용할수있다. unsigned long GetTargetThreadIdFromProcname(char *procname) PROCESSENTRY32 pe; HANDLE thsnapshot, hprocess; BOOL retval, ProcFound = false; unsigned long ptid, threadid; thsnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); if(thsnapshot == INVALID_HANDLE_VALUE) MessageBox(NULL, "Error: unable to create toolhelp snapshot", "Loader",
NULL); return false; pe.dwsize = sizeof(processentry32); retval = Process32First(thSnapshot, &pe); while(retval) if(strstri(pe.szexefile, procname) ) ProcFound = true; break; retval = Process32Next(thSnapshot,&pe); pe.dwsize = sizeof(processentry32); CloseHandle(thSnapshot); _asm mov eax, fs:[0x18] add eax, 36 mov [ptid], eax hprocess = OpenProcess(PROCESS_VM_READ, false, pe.th32processid);
ReadProcessMemory(hProcess, (const void *)ptid, &threadid, 4, NULL); CloseHandle(hProcess); return threadid; Appendix C - CreateRemoteThread complete example source code #include <windows.h> #include <stdio.h> #include <tlhelp32.h> #include <shlwapi.h> #define PROCESS_NAME "target.exe" #define DLL_NAME "injected.dll" //I could just use PROCESS_ALL_ACCESS but it's always best to use the absolute bare minimum of priveleges, so that your code works in as //many circumstances as possible. #define CREATE_THREAD_ACCESS (PROCESS_CREATE_THREAD PROCESS_QUERY_INFORMATION PROCESS_VM_OPERATION PROCESS_VM_WRITE PROCESS_VM_READ)
BOOL WriteProcessBYTES(HANDLE hprocess,lpvoid lpbaseaddress,lpcvoid lpbuffer,size_t nsize); BOOL LoadDll(char *procname, char *dllname); BOOL InjectDLL(DWORD ProcessID, char *dllname); unsigned long GetTargetProcessIdFromProcname(char *procname); bool IsWindowsNT() // check current version of Windows DWORD version = GetVersion(); // parse return DWORD majorversion = (DWORD)(LOBYTE(LOWORD(version))); DWORD minorversion = (DWORD)(HIBYTE(LOWORD(version))); return (version < 0x80000000); int WINAPI WinMain(HINSTANCE hinstance,hinstance hprevinstance,lpstr lpcmdline,int ncmdshow) if(iswindowsnt()) LoadDll(PROCESS_NAME, DLL_NAME); else MessageBox(0, "Your system does not support this method", "Error!", 0); return 0;
BOOL LoadDll(char *procname, char *dllname) DWORD ProcID = 0; ProcID = GetProcID(procName); if(!(injectdll(procid, dllname))) MessageBox(NULL, "Process located, but injection failed", "Loader", NULL); return true; BOOL InjectDLL(DWORD ProcessID, char *dllname) HANDLE Proc; char buf[50]=0; LPVOID RemoteString, LoadLibAddy; if(!processid) return false; Proc = OpenProcess(CREATE_THREAD_ACCESS, FALSE, ProcessID); if(!proc) sprintf(buf, "OpenProcess() failed: %d", GetLastError()); MessageBox(NULL, buf, "Loader", NULL); return false;
LoadLibAddy = (LPVOID)GetProcAddress(GetModuleHandle("kernel32.dll"), "LoadLibraryA"); RemoteString = (LPVOID)VirtualAllocEx(Proc, NULL, strlen(dll_name), MEM_RESERVE MEM_COMMIT, PAGE_READWRITE); WriteProcessMemory(Proc, (LPVOID)RemoteString, dllname, strlen(dllname), NULL); CreateRemoteThread(Proc, NULL, NULL, (LPTHREAD_START_ROUTINE)LoadLibAddy, (LPVOID)RemoteString, NULL, NULL); CloseHandle(Proc); return true; unsigned long GetTargetProcessIdFromProcname(char *procname) PROCESSENTRY32 pe; HANDLE thsnapshot; BOOL retval, ProcFound = false; thsnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); if(thsnapshot == INVALID_HANDLE_VALUE) MessageBox(NULL, "Error: unable to create toolhelp snapshot", "Loader", NULL);
return false; pe.dwsize = sizeof(processentry32); retval = Process32First(thSnapshot, &pe); while(retval) if(strstri(pe.szexefile, procname) ) ProcFound = true; break; retval = Process32Next(thSnapshot,&pe); pe.dwsize = sizeof(processentry32); return pe.th32processid; Appendix D - SetWindowsHookEx complete example source code
#include <windows.h> #include <tlhelp32.h> #define PROC_NAME "target.exe" #define DLL_NAME "injected.dll" void LoadDll(char *procname, char *dllname); unsigned long GetTargetThreadIdFromProcname(char *procname); int WINAPI WinMain(HINSTANCE hinstance,hinstance hprevinstance,lpstr lpcmdline,int ncmdshow) LoadDll(PROC_NAME, DLL_NAME); return 0; void LoadDll(char *procname, char *dllname) HMODULE hdll; unsigned long cbtprocaddr; hdll = LoadLibrary(dllName); cbtprocaddr = GetProcAddress(hDll, "CBTProc"); SetWindowsHookEx(WH_CBT, cbtprocaddr, hdll, GetTargetThreadIdFromProcName(procName));
return TRUE; unsigned long GetTargetThreadIdFromProcname(char *procname) PROCESSENTRY32 pe; HANDLE thsnapshot, hprocess; BOOL retval, ProcFound = false; unsigned long ptid, threadid; thsnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); if(thsnapshot == INVALID_HANDLE_VALUE) MessageBox(NULL, "Error: unable to create toolhelp snapshot", "Loader", NULL); return false; pe.dwsize = sizeof(processentry32); retval = Process32First(thSnapshot, &pe); while(retval) if(strstri(pe.szexefile, procname) ) ProcFound = true; break;
retval = Process32Next(thSnapshot,&pe); pe.dwsize = sizeof(processentry32); CloseHandle(thSnapshot); _asm mov eax, fs:[0x18] add eax, 36 mov [ptid], eax hprocess = OpenProcess(PROCESS_VM_READ, false, pe.th32processid); ReadProcessMemory(hProcess, (const void *)ptid, &threadid, 4, NULL); CloseHandle(hProcess); return threadid; Appendix E - Code cave example source code #include <windows.h>
#include <tlhelp32.h> #include <shlwapi.h> #define PROC_NAME "target.exe" #define DLL_NAME "injected.dll" unsigned long GetTargetProcessIdFromProcname(char *procname); unsigned long GetTargetThreadIdFromProcname(char *procname); declspec(naked) loaddll(void) _asm // Placeholder for the return address push 0xDEADBEEF // Save the flags and registers pushfd pushad // Placeholder for the string address and LoadLibrary push 0xDEADBEEF mov eax, 0xDEADBEEF // Call LoadLibrary with the string parameter call eax // Restore the registers and flags popad popfd
// Return control to the hijacked thread ret declspec(naked) loaddll_end(void) int WINAPI WinMain(HINSTANCE hinstance,hinstance hprevinstance,lpstr lpcmdline,int ncmdshow) void *dllstring; void *stub; unsigned long wowid, threadid, stublen, oldip, oldprot, loadlibaddy; HANDLE hprocess, hthread; CONTEXT ctx; stublen = (unsigned long)loaddll_end - (unsigned long)loaddll; loadlibaddy = (unsigned long)getprocaddress(getmodulehandle("kernel32.dll"), "LoadLibraryA"); wowid = GetTargetProcessIdFromProcname(PROC_NAME); hprocess = OpenProcess((PROCESS_VM_WRITE PROCESS_VM_OPERATION), false, wowid); dllstring = VirtualAllocEx(hProcess, NULL, (strlen(dll_name) + 1),
MEM_COMMIT, PAGE_READWRITE); stub = VirtualAllocEx(hProcess, NULL, stublen, MEM_COMMIT, PAGE_EXECUTE_READWRITE); WriteProcessMemory(hProcess, dllstring, DLL_NAME, strlen(dll_name), NULL); threadid = GetTargetThreadIdFromProcname(PROC_NAME); hthread = OpenThread((THREAD_GET_CONTEXT THREAD_SET_CONTEXT THREAD_SUSPEND_RESUME), false, threadid); SuspendThread(hThread); ctx.contextflags = CONTEXT_CONTROL; GetThreadContext(hThread, &ctx); oldip = ctx.eip; ctx.eip = (DWORD)stub; ctx.contextflags = CONTEXT_CONTROL; VirtualProtect(loadDll, stublen, PAGE_EXECUTE_READWRITE, &oldprot); memcpy((void *)((unsigned long)loaddll + 1), &oldip, 4); memcpy((void *)((unsigned long)loaddll + 8), &dllstring, 4); memcpy((void *)((unsigned long)loaddll + 13), &loadlibaddy, 4); WriteProcessMemory(hProcess, stub, loaddll, stublen, NULL); SetThreadContext(hThread, &ctx); ResumeThread(hThread); Sleep(8000); VirtualFreeEx(hProcess, dllstring, strlen(dll_name), MEM_DECOMMIT);
VirtualFreeEx(hProcess, stub, stublen, MEM_DECOMMIT); CloseHandle(hProcess); CloseHandle(hThread); return 0; unsigned long GetTargetProcessIdFromProcname(char *procname) PROCESSENTRY32 pe; HANDLE thsnapshot; BOOL retval, ProcFound = false; thsnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); if(thsnapshot == INVALID_HANDLE_VALUE) MessageBox(NULL, "Error: unable to create toolhelp snapshot", "Loader", NULL); return false; pe.dwsize = sizeof(processentry32); retval = Process32First(thSnapshot, &pe); while(retval) if(strstri(pe.szexefile, procname) )
ProcFound = true; break; retval = Process32Next(thSnapshot,&pe); pe.dwsize = sizeof(processentry32); CloseHandle(thSnapshot); return pe.th32processid; unsigned long GetTargetThreadIdFromProcname(char *procname) PROCESSENTRY32 pe; HANDLE thsnapshot, hprocess; BOOL retval, ProcFound = false; unsigned long ptid, threadid; thsnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); if(thsnapshot == INVALID_HANDLE_VALUE) MessageBox(NULL, "Error: unable to create toolhelp snapshot", "Loader", NULL); return false; pe.dwsize = sizeof(processentry32);
retval = Process32First(thSnapshot, &pe); while(retval) if(strstri(pe.szexefile, procname) ) ProcFound = true; break; retval = Process32Next(thSnapshot,&pe); pe.dwsize = sizeof(processentry32); CloseHandle(thSnapshot); _asm mov eax, fs:[0x18] add eax, 36 mov [ptid], eax hprocess = OpenProcess(PROCESS_VM_READ, false, pe.th32processid); ReadProcessMemory(hProcess, (const void *)ptid, &threadid, 4, NULL); CloseHandle(hProcess); return threadid;