殼的編寫(3) 編寫殼 Stub 部分(2)

2021-07-09 07:14:15 字數 3435 閱讀 1691

接:殼的編寫(2)-- 編寫殼(stub)部分(1)  

由於我們程式到時會丟棄掉自己的iat和匯入表資訊,這樣就不能夠直接呼叫api,因此,我們需要使用動態載入api方法。我們需要獲取到getprocaddress函式的位址,而該函式是從系統檔案kernel32.dll中匯出的,所有的執行的程式都會載入該動態鏈結庫。那麼,我們獲取到kernel32.dll載入基址,就可以獲取getprocaddress函式了。要想獲取到kernel32基址,我們可以使用teb的資訊找到kernel32.dll的載入基址:

1)通過fs得到teb的位址

2)teb偏移0x30處指向的是peb指標

3)peb偏移0x0c處指向peb_ldr_data結構指標

4)peb_ldr_data偏移0x1c處是ininitializationordermodulelis(模組初始化鍊錶的頭指標)

5)ininitializationordermodulelis中按順序存在著此程序的初始化模組資訊,在nt5.x核心中,第乙個節點為ntdll.dll的基址,第二個節點為kernel32.dll的基址; 在nt6.1核心中,第二個節點為kernelbase.dll的基址(包含著kernel32.dll的大部分實現,其中就有getprocaddress函式)

為此我們需要在stub.h中定義兩個函式,乙個用於獲取kernel32.dll基址,乙個用於獲取getprocaddress基址,**如下:

extern dword getkernel32base();   // 獲取kernel32.dll的模組基址

extern dword getgpafunaddr(); // 獲取getprocaddress的函式位址

在stub.cpp中獲取kernel32.dll的**如下:

dword getkernel32base()

return dwkernel32addr;

}

此時我們就能夠獲取到kernel32.dll的基址,那麼就可以通過遍歷kernel32.dll的匯出表獲取到getprocaddress函式的基址了。

在stub.cpp檔案中獲取getprocaddress的基址**如下:

dword getgpafunaddr()

// 4.1 獲取序號

dword dwid = pexport->base + i;

// 4.2 變數eit 從中獲取到 getprocaddress的位址

for (dword dwidx = 0; dwidx < dwnamecount; dwidx++)

}} }

return -1;

}

extern bool  initializationapi(); // 初始化各個api

// 基礎api定義宣告

typedef dword (winapi *lpgetprocaddress)(hmodule,lpcstr); // getprocaddress

typedef hmodule (winapi *lploadlibraryex)(lpctstr,handle,dword); // loadlibaryex

extern lpgetprocaddress g_fungetprocaddress;

extern lploadlibraryex g_funloadlibraryex;

// 其他api定義宣告

typedef void (winapi *lpexitprocess)(uint); // exitprocess

typedef int (winapi *lpmessagebox)(hwnd,lpctstr,lpctstr,uint); // messagebox

typedef hmodule (winapi *lpgetmodulehandle)(lpcwstr); // getmodulehandle

typedef bool (winapi *lpvirtualprotect)(lpvoid,size_t,dword,pdword); // virtualprotect

extern lpexitprocess g_funexitprocess;

extern lpmessagebox g_funmessagebox;

extern lpgetmodulehandle g_fungetmodulehandle;

extern lpvirtualprotect g_funvirtualprotect;

在stub.cpp中實現initializationapi函式,並初始化要使用的api函式。由於kernelbase.dll中沒有匯出loadlibrary函式,所以為了相容性考慮,我們在載入dll的時候使用loadlibraryexw。

lpgetprocaddress  g_fungetprocaddress = nullptr;

lploadlibraryex g_funloadlibraryex = nullptr;

lpexitprocess g_funexitprocess = nullptr;

lpmessagebox g_funmessagebox = nullptr;

lpgetmodulehandle g_fungetmodulehandle = nullptr;

lpvirtualprotect g_funvirtualprotect = nullptr;

bool initializationapi()

在stub.h中定義乙個加密函式

extern void  decrypt();           // 解密函式
在stub.cpp中實現該函式

void decrypt()

}

我們先初始化global_param結構,並在start函式中呼叫initializationapi()初始化所有api ,調動decrypt()進行解密,並跳轉到被加殼程式的原始oep。

extern __declspec(dllexport) global_param g_stcparam=;

void start()

為了退出程序時的相容性,在stubentrypoint中新增退出程序的相容**,總體如下:

void __declspec(naked) stubentrypoint()

__asm retn;

}

編寫自己的shell(2)

指令碼中除了命令之外還包括以下元素 變數,使用者輸入,控制流,環境變數。上一次用fork,execvp,wait實現了乙個能夠建立程序和執行程式的shell。此次對這個shell做一些改進。加入命令列解析,這樣使用者可以在一行中輸入命令和所有引數了,然後將控制語句if.then加入到這個shell中...

再說C模組的編寫(2)

前言 在 再說c模組的編寫 1 中主要總結了lua呼叫c函式時,對陣列和字串的操作,而這篇文章將重點總結如何在c函式中儲存狀態。什麼叫做在c函式中儲存狀態?比如你現在使用lua呼叫了c函式func1,但是func1中有一些資料在呼叫完以後儲存下來,供以後使用。而這些資料就是所謂的狀態,也就是我們需要...

運維標書技術部分的編寫

一 運維招標的由來 當乙個軟體專案結項以後,往往有一段時間 一般為一年 的免費運維服務。如一年以後專案仍在甲方執行,該年度的軟體運維則以運維服務形式向運維商招標。最常見的如防毒軟體的年度服務費。就當今現狀,其一甲方 多為 或事業單位 不會編寫招標檔案,其扮演的角色多為管理和組織 也就是提要求 實施多...