接:殼的編寫(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中有一些資料在呼叫完以後儲存下來,供以後使用。而這些資料就是所謂的狀態,也就是我們需要...
運維標書技術部分的編寫
一 運維招標的由來 當乙個軟體專案結項以後,往往有一段時間 一般為一年 的免費運維服務。如一年以後專案仍在甲方執行,該年度的軟體運維則以運維服務形式向運維商招標。最常見的如防毒軟體的年度服務費。就當今現狀,其一甲方 多為 或事業單位 不會編寫招標檔案,其扮演的角色多為管理和組織 也就是提要求 實施多...