惡意代碼分析之注入技術(shù)? 在很多時候?yàn)榱四軌驅(qū)δ繕?biāo)進(jìn)程空間數(shù)據(jù)進(jìn)行修改,或者使用目標(biāo)進(jìn)程的名稱來執(zhí)行自己的代碼,實(shí)現(xiàn)危害用戶的操作,通常是將一個 全局鉤子注入? 在Windows中大部份的應(yīng)用程序都是基于消息機(jī)制的,他們都有一個消息過程函數(shù),根據(jù)消息完成不同的功能。Windows操作系統(tǒng)提供的鉤子機(jī)制就是用來截獲和監(jiān)視這些消息的。按照鉤子的范圍不同,它們又可以分為局部鉤子和全局鉤子,局部鉤子是針對某個線程的;而全局鉤子則是作用于整個系統(tǒng)的基于消息的應(yīng)用。全局鉤子需要使用
成功返回
遠(yuǎn)程線程注入遠(yuǎn)程線程注入是指一個進(jìn)程在另一個進(jìn)程中創(chuàng)建線程的技術(shù),是一種經(jīng)典的注入技術(shù)
指定進(jìn)程的虛擬地址空間內(nèi)保留、提交或者更改內(nèi)存的狀態(tài)
? 從以上這些函數(shù)的作用我們實(shí)現(xiàn)的原理就很清晰了,先在指定進(jìn)程申請一段地址然后將準(zhǔn)備好的 ? 注意:對于一些系統(tǒng)服務(wù)這樣通常會注入失敗,由于系統(tǒng)存在SESSION 0隔離的安全機(jī)制,需調(diào)用一個更加底層的
|
| 語言 | 方法 |
|---|---|
| 7279 | 6JQ2GywG8D |
| EIwRA | 緒川里緒 |
| 8742 | 2010.09.08 05-16-01 |
? APC的注入原理是利用當(dāng)線程被喚醒時APC中的注冊函數(shù)會執(zhí)行的機(jī)制,并以此去執(zhí)行DLL加載代碼,進(jìn)而完成DLL注入。為了增加成功率,可以向目標(biāo)進(jìn)程中的所有線程都插入APC。
inlineHOOKIATHOOKinlineHook是一種通過修改機(jī)器碼的方式來實(shí)現(xiàn)HOOK的技術(shù)原理:對于一個正常的程序如下圖,通過CALL指令來調(diào)用函數(shù)。關(guān)于CALL指令相當(dāng)于push 當(dāng)前函數(shù)地址和jmp要執(zhí)行的指令位置,即 push 0171B7B3 jmp 0171B430,這是我們正常執(zhí)行00.0171B430這個函數(shù)的樣子。

我們在hook的時候就是將CALL指令直接改成jmp指令,跳到我們自己編寫的函數(shù)的位置,執(zhí)行完成之后跳回函數(shù)原來指令的下一條指令0171B7B3,需要注意的是跳轉(zhuǎn)偏移要多計(jì)算5個字節(jié)
計(jì)算公式: 跳轉(zhuǎn)偏移 = 目標(biāo)地址 - jmp所在的地址 - 5
void OnHook() {
//獲取函數(shù)實(shí)際地址
HMODULE Module = GetModuleHandleA("kernel32.dll");
LPVOID func = GetProcAddress(Module, "OpenProcess");
//保存5個字節(jié)
memcpy(g_oldCode, func, 5);
//修改內(nèi)存分頁屬性,由于代碼段是不可寫的,所有必須先將它的屬性變成可寫
DWORD dwProtect;
VirtualProtect(func, 5, PAGE_EXECUTE_READWRITE, &dwProtect);
//計(jì)算跳轉(zhuǎn)偏移
*(DWORD*)&g_newCode[1] = (DWORD)MyOpenProcess - (DWORD)func - 5;
//修改目標(biāo)地址
memcpy(func, g_newCode, 5);
//還原內(nèi)存分頁屬性
VirtualProtect(func, 5, dwProtect, &dwProtect);
};
IATHook是通過替換IAT表中函數(shù)的原始地址從而實(shí)現(xiàn)的Hook? 與普通的InlineHook不一樣,IATHook需要充分理解PE文件的結(jié)構(gòu)才能完成,關(guān)于相對虛擬地址(RVA)、文件偏移地址(FOA)和加載基址等概念可以自行查閱相關(guān)資料。
//獲取指定dll導(dǎo)出地址表的中函數(shù)地址
DWORD * GetIatAddress(const char * dllName, const char* funName) {
// 1. 獲取加載基址并轉(zhuǎn)換成DOS頭
auto DosHeader = (PIMAGE_DOS_HEADER)GetModuleHandle(NULL);
// 2. 通過 DOS 頭的后一個字段 e_lfanew 找到 NT 頭的偏移
auto NtHeader = (PIMAGE_NT_HEADERS)(DosHeader->e_lfanew + (DWORD)DosHeader);
// 3. 在數(shù)據(jù)目錄表下標(biāo)為[1]的地方找到導(dǎo)入表的RVA
DWORD ImpRVA = NtHeader->OptionalHeader.DataDirectory[1].VirtualAddress;
// 4. 獲取到導(dǎo)入表結(jié)構(gòu)體,因?yàn)槌绦蛞呀?jīng)運(yùn)行了,所以不需要轉(zhuǎn)FOA
auto ImpTable = (PIMAGE_IMPORT_DESCRIPTOR)((DWORD)DosHeader + ImpRVA);
// 遍歷導(dǎo)入表,以一組全0的結(jié)構(gòu)結(jié)尾
while (ImpTable->Name)
{
// 獲取當(dāng)前導(dǎo)入表結(jié)構(gòu)描述的結(jié)構(gòu)體的名稱
CHAR* Name = (CHAR*)(ImpTable->Name + (DWORD)DosHeader);
// 忽略大小寫進(jìn)行比較,查看是否是需要的導(dǎo)入表結(jié)構(gòu)
if (!_stricmp(Name, dllName))
{
// 找到對應(yīng)的 INT 表以及 IAT 表
DWORD* IntTable = (DWORD*)((DWORD)DosHeader + ImpTable->OriginalFirstThunk);
DWORD* IatTable = (DWORD*)((DWORD)DosHeader + ImpTable->FirstThunk);
// 遍歷所有的函數(shù)名稱,包括有/沒有名稱
for (int i = 0; IntTable[i] != 0; ++i)
{
// 比對函數(shù)是否存在函數(shù)名稱表中
if ((IntTable[i] & 0x80000000) == 0)
{
// 獲取到導(dǎo)入名稱結(jié)構(gòu)
auto Name = (PIMAGE_IMPORT_BY_NAME)((DWORD)DosHeader + IntTable[i]);
// 比對函數(shù)的名稱
if (!strcmp(funName, Name->Name))
{
// 返回函數(shù)在IAT中保存的地址
return &IatTable[i];
}
}
}
}
ImpTable++;
}
return 0;
}
? 鉤子技術(shù)總結(jié)起來就是通過各種手段來修改代碼或者地址從而讓程序來執(zhí)行我們自己編寫的代碼,在分析惡意程序時關(guān)注一下這些敏感的API函數(shù)組合,在查看程序基本信息的時候就可以大致做出猜測。下一篇繼續(xù)分享常見的啟動和隱藏技術(shù),繼續(xù)刨析病毒的實(shí)現(xiàn)原理。
|
|
來自: 昵稱70680357 > 《待分類》