1.先寫個(gè)我們要調(diào)用的函數(shù)
#include<iostream> using?namespace?std; void?test(int?a,?int&?b) { cout?<<?a?<<?b?<<?endl; b?=?a?+?b; } void?main() { int?a?=?2; int?b=0; test(a,?b); cout?<<?b?<<?endl; system("pause"); }
這個(gè)我們寫了一個(gè)很簡單的函數(shù),一個(gè)main函數(shù)和test函數(shù)。我們后面要通過動(dòng)態(tài)注入dll調(diào)用這個(gè)test函數(shù)。
我們先運(yùn)行一下??纯唇Y(jié)果
20 2 請按任意鍵繼續(xù). . .
輸入這個(gè),看了沒有任何問題。
2.寫一個(gè)簡單的dll
?switch?(ul_reason_for_call) ? { ? ?case?DLL_PROCESS_ATTACH: { ? ? ? ?MessageBox(GetForegroundWindow(),?L"測試",?L"成功注入",?1); ? ? ? ? ? ? } ? ? ? ? ?case?DLL_THREAD_ATTACH: ? ?case?DLL_THREAD_DETACH: ? ?case?DLL_PROCESS_DETACH: ? ? ? ?break; ? }
我們在vs2019創(chuàng)建一個(gè)dll文件,在DLL_PROCESS_ATTACH下面加一行語句。
MessageBox(GetForegroundWindow(), L"測試", L"成功注入", 1); ?
這個(gè)是用來測試我們后面注入dll彈出的窗口。
3.寫注入程序
#include<windows.h> #include"tchar.h" #include<stdio.h> int get_id(LPCTSTR name) { HWND hWnd = FindWindow(NULL,name); if (hWnd == NULL){//如果無法獲取句柄則報(bào)錯(cuò) printf("無法獲取窗口句柄,請檢查進(jìn)程是否存在!\n"); system("pause"); return -1; } DWORD pro_id; GetWindowThreadProcessId(hWnd, &pro_id);//獲取進(jìn)程ID ? if(pro_id == 0){ printf("無法獲取進(jìn)程ID\n"); system("pause"); return 0; } printf("進(jìn)程id: %d\n",pro_id); //打開進(jìn)程對象,并獲取進(jìn)程句柄 /*ANDLE hpro = OpenProcess(PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ, FALSE, pro_id); if (hpro == 0){ printf("無法獲取進(jìn)程句柄"); } printf("進(jìn)程句柄id: %d\n",hpro); */ return (int)pro_id; } BOOL InjectDll(LPCTSTR szDllPath, LPCTSTR name) { DWORD dwPID = (DWORD)get_id(name); HANDLE hProcess = NULL, hThread = NULL; HMODULE hMod = NULL; LPVOID pRemoteBuf = NULL; DWORD dwBufSize = (DWORD)(_tcslen(szDllPath) + 1) * sizeof(TCHAR); LPTHREAD_START_ROUTINE pThreadProc; //1.使用dwPID獲取目標(biāo)進(jìn)程句柄 if (!(hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPID))) { _tprintf(L"OpenProcess(%d) failed!![%d]\n", dwPID, GetLastError()); return FALSE; } //2.在目標(biāo)進(jìn)程中分配szDllName大小的內(nèi)存 pRemoteBuf = VirtualAllocEx(hProcess, NULL, dwBufSize , MEM_COMMIT, PAGE_READWRITE); //3.將myhack.dll路徑寫入分配的內(nèi)存。 WriteProcessMemory(hProcess, pRemoteBuf, (LPVOID)szDllPath, dwBufSize, NULL); //4.獲取LoadLibrary()API的地址 hMod = GetModuleHandle(L"kernel32.dll"); pThreadProc = (LPTHREAD_START_ROUTINE)GetProcAddress(hMod, "LoadLibraryW"); //5.在notepad中運(yùn)行線程. hThread = CreateRemoteThread(hProcess, NULL, 0, pThreadProc, pRemoteBuf, 0, NULL); WaitForSingleObject(hThread, INFINITE); //CloseHandle(hThread); //CloseHandle(hProcess); return TRUE; } int _tmain(int argc, TCHAR *argv[]) { //injectdll if (InjectDll(argv[1],argv[2])) _tprintf(L"InjectDll(\"%s\") sucess!!!\n", argv[2]); //MessageBox(NULL, TEXT("1"), TEXT("warn"), 0); else _tprintf(L"InjectDll(\"%s\") failed!!!\n", argv[2]); //MessageBox(NULL, TEXT("2"), TEXT("warn"), 0); }
這個(gè)程序的話,我是直接從網(wǎng)上拿的,拿過來改了一點(diǎn),打包成exe,通過命令行進(jìn)行調(diào)用。
4.測試注入
注入.exe 注入dll.dll test.exe
在命令行里面就這樣進(jìn)行調(diào)用。這個(gè)test.exe就是你程序的名字,你可以用vs2019的spy+=進(jìn)行查看,就是你的程序標(biāo)題
調(diào)用成功的話,會(huì)自動(dòng)彈出這個(gè)。
5.完善dll程序
我們的目標(biāo)是在dll調(diào)用到test.exe的test函數(shù),這個(gè)dll還沒有達(dá)到我們的目標(biāo),我們還需要繼續(xù)完善。
我們想調(diào)用test函數(shù),就必須知道這個(gè)函數(shù)在內(nèi)存的地址,但是每次重啟電腦,地址都是變化的。我們需要找到基址。這里我們改一下dll,讓他輸出程序的基址
switch (ul_reason_for_call) ? { ? case DLL_PROCESS_ATTACH: { ? ? ? MessageBox(GetForegroundWindow(), L"測試", L"成功注入", 1); ? ? ? ? ? ? ? ? ? HMODULE hModule = GetModuleHandle(NULL); ? ? ? ? ? WCHAR wszhModule[MAX_PATH] = {0}; ? ? ? ? ? ? swprintf_s(wszhModule, L"DLL里調(diào)用GetModuleHandle(NULL)獲取到的地址為:0x%x", \ ? ? ? ? ? ? ? (DWORD)hModule); ? ? ? ? ? MessageBoxW(0, wszhModule, L"提示", 0); ? } ? ? ? ? case DLL_THREAD_ATTACH: ? case DLL_THREAD_DETACH: ? case DLL_PROCESS_DETACH: ? ? ? break; ? }
我們重新生成,再次注入試試。
記住這個(gè)地址,后面我們需要這個(gè)地址。
我們打開x64dbg來進(jìn)行調(diào)試。我們把生成的test.exe進(jìn)行調(diào)試。這個(gè)自己寫的代碼找起來還是比較容易的
007919CF | C745 F4 02000000 ? ? ? ? | mov dword ptr ss:[ebp-C],2 ? ? ? ? ? ? |將2推入棧中 007919D6 | C745 E8 00000000 ? ? ? ? | mov dword ptr ss:[ebp-18],0 ? ? ? ? ? ? |將0推到棧中 007919DD | 8D45 E8 ? ? ? ? ? ? ? ? | lea eax,dword ptr ss:[ebp-18] ? ? ? ? ? |將0的地址放到eax里面 007919E0 | 50 ? ? ? ? ? ? ? ? ? ? ? | push eax ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? |將eax推入棧中 007919E1 | 8B4D F4 ? ? ? ? ? ? ? ? | mov ecx,dword ptr ss:[ebp-C] ? ? ? ? ? |將2給ecx 007919E4 | 51 ? ? ? ? ? ? ? ? ? ? ? | push ecx ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? |將ecx推入棧中 007919E5 | E8 F2F6FFFF ? ? ? ? ? ? | call test.7910DC ? ? ? ? ? ? ? ? ? ? ? |這個(gè)就是test的call 007919EA | 83C4 08 ? ? ? ? ? ? ? ? | add esp,8 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? |還原堆棧
我們可以找到這個(gè)代碼,我們找到call的地址7910dc。和之前的0x780000相減得到偏移0x110DC。有了這個(gè)偏移,我們后面就可以直接調(diào)用這個(gè)call了。
接下來,我們寫一個(gè)函數(shù)
void zhu(DWORD baseaddr) { ? DWORD dwCallAddr = baseaddr + (DWORD)0x110DC; ? printf("%x\n", (int)dwCallAddr); ? int a = 2; ? int& r = a; ? __asm { ? ? ? push r ? ? ? push a ? ? ? call dwCallAddr ? ? ? add esp,8 ? } ? printf("%d", r); }
這個(gè)函數(shù)很簡單,里面內(nèi)嵌的匯編代碼,用來調(diào)用test的call,首先我們申明一個(gè)a=2,和一個(gè)引用類型r。先push r,在push a。這個(gè)可以和上面拿到的匯編進(jìn)行對比,這個(gè)是按照c語言的調(diào)用約定來的,這個(gè)push的順序是不能變的哈,后面直接調(diào)用call。后面用add esp,8來還原堆棧。不然會(huì)報(bào)錯(cuò)。接下來就將zhu函數(shù)放到DLL_PROCESS_ATTACH下面進(jìn)行調(diào)用
6.進(jìn)行測試
將dll和注入exe,以及測試程序都放到同一個(gè)文件夾,dll和測試程序一定要同一個(gè)文件夾哦,然后打開cmd,輸入命令。開始測試。不出意外的話,應(yīng)該會(huì)彈出兩個(gè)窗口,一個(gè)是注入成功窗口,一個(gè)是輸出基址的窗口。接著輸出結(jié)果也會(huì)變文章來源:http://www.zghlxwxcb.cn/news/detail-438662.html
20 2 請按任意鍵繼續(xù). . . 7910dc 22 4
會(huì)變成這樣,可以看到我們順利調(diào)用了這個(gè)test的test函數(shù)文章來源地址http://www.zghlxwxcb.cn/news/detail-438662.html
到了這里,關(guān)于c++注入dll調(diào)用call的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!