動態載入dll的實現
1.在目標程序中申請記憶體
2.向目標程序記憶體中寫入shellcode(沒有特徵,編碼比較麻煩)
3.建立遠執行緒執行shellcode
之前可以看到shellcode很難編寫還要去依賴庫,去字串區等等很麻煩,為了讓被注入程式碼更容易編寫,最好的方法就是通過dll來編寫
dll載入:
1.靜態呼叫:通過在我們的程式中新增標頭檔案,以及lib檔案來完成呼叫,前提就是獲取dll然後還有標頭檔案
2.動態呼叫:僅僅只需要一個dll即可完成呼叫
先寫個試一下
#include <Windows.h> __declspec(dllexport) void Test(){ MessageBox(NULL, NULL, NULL, NULL); }
可以看到我們的Test,但是這種方式會對Test進行名稱粉碎,由c++編譯器新增的,需要告訴編譯器使用c的方式來命名函式,所以我們這麼寫,然後還需要指明函式引數的呼叫約定
1.__stdcall 標準 棧傳參,函式內部(被呼叫者)平棧
2. __cdecl c 棧傳參,函式外部(呼叫者)平棧
3. __fastcall 快速 暫存器傳參
4. __thiscall 類的thiscall呼叫約定,使用ecx暫存器來傳遞this指標
extern "C"{ __declspec(dllexport) void __stdcall Test(){ MessageBox(NULL, NULL, NULL, NULL); } }
上面寫到__stdcall是函式內部平參這裡來看看
void __stdcall test(int n1, int n2){
return;
}
int main()
{
test(1, 2);
return 0;
}
兩個返回8一個返回4
void __stdcall test(int n1, int n2){ 002013C0 push ebp 002013C1 mov ebp,esp 002013C3 sub esp,0C0h 002013C9 push ebx 002013CA push esi 002013CB push edi 002013CC lea edi,[ebp-0C0h] 002013D2 mov ecx,30h 002013D7 mov eax,0CCCCCCCCh 002013DC rep stos dword ptr es:[edi] return; } 002013DE pop edi 002013DF pop esi 002013E0 pop ebx 002013E1 mov esp,ebp 002013E3 pop ebp 002013E4 ret 8
很明顯改變了引數返回的時候值就會變化而且是函式內部的變化所以是函式內部平棧,絕大部分的windows api都是stdcall,但是也有特例,比如wsprintf
char szBuf[256] = {0};
wsprintfA(szBuf,"%s","1234");
這裡很明顯因為他是由外界傳入的引數來決定多少,所以是函式外部平參
繼續回到動態載入dll
1.將目標dll載入到我們程序中
HMODULE hDll = LoadLibraryA("./TestDLL.dll");
返回值是模組控制代碼
這裡就可以看到我們的dll完全被載入到我們的記憶體裡面來了,所以說返回的模組控制代碼也就是當前dll在當前程序中的首地址,載入過程是由我們的作業系統來完成的(包括各節的擴充套件分配記憶體,重定位等等),有時候也可以自己寫loadlibraby因為用這個函式太官方了,自己寫就叫做記憶體載入,這是很多病毒的手法
2.計算函式的位置
都有個偏移
可以看到偏移是11122
LPVOID lp = GetProcAddress(hDll, "Test");
可以看到20000+11122 = 31122
也可以寫個def
LIBRARY
EXPORTS
Test
這裡得到的就是個函式指標
typedef void(*PFN_FPP)();
PFN_FPP lp = (PFN_FPP)GetProcAddress(hDll, "Test");
最後再呼叫就可以了
lp();
但是如何要求目標程序呼叫Loadlibrary來載入我們的dll,最後執行我們的dll中的匯出函式
可以看到Loadlibrary是存在於Kernel32.dll中的,所以先去找目標程序中的Kernel32.dll的位置,一般程式中都有Kernel32.dll這個,因為他是個很基本的dll
然後再找到該dll匯出的loadlibraryA或W函式的位置