上一次做完程式碼段加密後,又接觸到了新的加密方式:IAT加密
IAT加密是通過隱藏程式的匯入表資訊,以達到增加分析程式的難度。因為沒有匯入表,就無法單純的從靜態狀態下分析呼叫了什麼函式,動態除錯時,也無法直接從呼叫處判斷出呼叫的函式。從而增加了程式分析的難度。
IAT加密思路如下:
1.把IAT資訊全部刪除掉,只留下DLL名和第一個呼叫函式的資訊(目的是讓程式在最開始執行時能正常呼叫那些初始化類的函式)
2.根據匯入表的資訊,自己實現函式載入,通過LoadLibraryA和GetProcAddress函式把DLL中的所有函式載入進來,並在程式中儲存載入後的函式地址。(但由於是用程式A給程式B加密,程式B未執行時,如何獲得這2個函式的地址呢?而且IAT表也已經被刪掉了。此時只能藉助PEB和TEB來獲取這2個函式的地址,並記錄在程式B中,當程式B執行時,就可以通過對應的位置取得函式地址)
3.找到所有 “指令中包含了IAT載入地址” 的指令,並記錄這些指令的位置(指令所在位置而不是指令中的地址位置)
4.構建一個shellcode表,裡面寫著每個3.裡所找到的指令的處理程式碼,簡單來說就是把3.所找到的地址,修改成跳到4的這個shellcode表對應的處理指令中,這段處理指令實現和3.的指令一樣的效果。
5.把3.中的指令修改為一個jmp,jmp到4.中對應的處理程式碼。實現一樣的效果。
6.把重定位表中,有關於IAT表的項刪掉,因為IAT加密後,原呼叫位置的指令是跳轉到自己寫的shellcode中,裡面的指令是在函式執行後修改的。無需重定位了。
實現步驟:
1.先常規的檢查該程式是否為PE檔案(檢查"MZ"和“PE”是否存在)
2.通過匯入表,找到對應的IAT值,並構建一個向量vector用於儲存。(注:這裡為IAT的值,而不是IAT的值指向的地址中的值)
3.根據2.中所找到的IAT,找到在原始檔中,又那些是使用了這個值的,分別是mov exx(每個暫存器對應的二進位制數不同),push,call,jmp。記得這裡記錄的是呼叫指令的位置,而不是呼叫指令中IAT地址所在的位置
4.用向量vector+結構體的方式先將IAT表中的資訊儲存下來(DLL個數,每個DLL的名及名字的長度。這個DLL是通過什麼方式匯出函式(名稱/序號);DLL有幾個匯出函式,他們分別的值是多少,如果他是以名稱匯出的話,該名稱的長度和值分別又是多少)。
5.接著隱藏被加密檔案的匯入表,每個DLL下面的INT和IAT表只保留第一個值,其他的全部賦值為0,去除掉匯入資訊
6.更新重定位表資料,如果沒有重定位表則跳過這項。看7.
6.1先把重定位表的值儲存下來,以便後續移動到程式末尾(這麼做的目的是為了後續新增新的重定位項時,重定位塊的範圍能覆蓋上) (例:當前程式最大記憶體偏移為0x15000,增加後的偏移為0x18000,如果不把重定位移到最後的話,新增加的這0x3000中就無法被重定位到)
6.2把目標程式的重定位表資料清空
7.將每個節的保護屬性修改為可寫(本來只修改.text節的屬性即可,但由於該節的位置不在data陣列裡面記錄,單憑節名判斷未必準確,所以將所以節都改為可寫)
8.建立一個新的節,把4中儲存的匯入表資訊填充進去。由於已知這些資訊的長度,寫shellcode時把位置一一對應即可。
8.1再在這個節當中,申請匯入函式個數*4的空間,以便存放後續匯入的函式地址
8.2記錄當前的記憶體地址,設為新的OEP;
8.3最為重要的一點:編寫shellcode
8.3.1:由於LoadLibraryA和GetProcAddress都為Kernel32中的匯出函式;所以先通過程式的fs:[0x30]獲取到PEB結構,再在該結構的0x0C的位置獲取到該程式的DLL列表指標,再通過這個列表的0x1C的位置獲取初始化模組列表;通過這個初始化模組列表取得結構,對比結構成員中的長度和值,取到目標DLL(Kernel32.dll)在該程式的裝載基址
8.3.2獲得Kernel32的裝載基址後,把該地址當成一個PE檔案處理,通過偏移取值,最後找到匯出表位置,根據匯出表中的資料一一比對,得到LoadLibraryA和GetProcAddress在該程式的位置。儲存起來
8.3.3根據8中儲存的匯入表資料,一一呼叫LoadLibraryA獲得目標DLL的裝載地址,再根據該裝載地址,呼叫GetProcAddress把其中的函式地址全部獲取出來,並按匯入表的順序,儲存到8.1所預留出來的空間中
8.3.4構造代替原匯入表功能的shellcode塊,每個shellcode塊對應一個使用到IAT地址的位置(2.所儲存的值)。
8.3.5把原呼叫到IAT指令的位置,全部修改為jmp到8.3.4對應的shellcode塊,注意指令長度,替換後的指令為jmp [目標shellcode塊地址],佔5位元組,如原指令佔6位元組的話,填充一個nop對齊 流程為:找到呼叫IAT地址的指令位置(3.中儲存了),將其替換成jmp [對應shellcode塊地址],在對應shellcode塊中,把自己在8.3.3所獲得的函式地址,用混淆的方式,實現成原來的功能。(本來為mov eax [iat地址],修改成JMP 對應shellcode塊,對應shellcode塊裡實現mov eax [自己所獲得的函式地址])
9.如果沒有重定位表跳過這一步,看10. 把重定位把重定位表中有關呼叫函式的指令位置刪掉(注:這裡的位置為指令當中的地址的位置,例:E9 0X0123 4567在0x8的位置,那麼地址位置就為0x9)。這麼做的目的是因為IAT表加密後,函式都是自己實現匯入的,原匯入表的這些項無需再進行重定位了,填充時地址就已經是當前程式的位置了。
10.由於8.3.4的shellcode塊中需要用到基址,這裡利用了重定位表的方式獲得基址,所以要把每個shellcode塊中,對應獲得基址的指令地址也新增到重定位塊中
11.將新增的節按檔案對齊和記憶體對齊後,將重定位表恢復,恢復起始位置為新增節的起始位置+對齊後的大小
11.IAT加密完成
下面附上程式碼:
程式碼長度1594 未精簡,有備註 其中有涉及jit編譯shellcode指令的程式碼,所以無法直接複製執行,這裡僅提供編寫思路。
1 #include<iostream> 2 #include<Windows.h> 3 #include<map> 4 #include<vector> 5 #include "Asmjit\\asmjit.h" 6 7 using namespace std; 8 using namespace asmjit; 9 using namespace asmjit::x86; 10 11 int g_iFileSize = 0; //檔案大小 12 UCHAR *g_pFileSrc = NULL; //檔案內容 (此處必須為無符號字元指標,因為char會將十六進位制的最高位預設為符號位) 13 int g_iSectionAlignment = 0;//記憶體對齊大小 14 int g_iFileAlignment = 0;//檔案對齊大小 15 int g_iImageBase = 0;//程式基址 16 int g_iNewOEP = 0;//新入口點 17 int g_iOldOEP = 0;//舊入口點 18 19 struct FuncTag 20 { 21 BYTE iFuncNameLenth;//函式名稱長度 22 char *szFuncName; 23 }; 24 struct DLLFuncTag 25 { 26 byte bDllNameLenth;//DLL名長度 27 char *szDllName; 28 WORD wFuncNum;//當前DLL的函式數量 29 byte bTab;//匯入方式:0為序號匯入 1為名稱 30 vector<FuncTag>vFuncNAMEorNo;//注意:此時的序號已經去掉最高位 31 }; 32 vector<DLLFuncTag>g_tagDllFunc;//存放IAT資訊的結構體,成員為DLL名長度,DLL名,函式數量,標誌(最高位為1則是序號,否則為一個字串的地址),函式名列表 33 34 35 //先通過遍歷獲得下面結構體中各個成員的值 注:成員的位置皆為RVA 36 /* 37 1.將dwRelocAddr這4位元組的地址放入重定位表中,使其在執行後該位置的值變為程式基址 38 2.先去dwCallAddr的位置,將那行程式碼修改為jmp dwJmpAddr(如果是mov eax,則直接修改即可,其他的則要填充多一個nop(0x90),以便對齊指令長度) 39 3.執行shellcode時,會將2的呼叫地址+5/+6作為返回地址壓棧 (jmp指令除外) 40 4.將NewLatAddr的值,加上基址後,在得到的地址上取值,該地址上的值與原IAT所指向的值相同 41 5.執行完後,根據3得到的值,返回到呼叫指令的下一條指令上 42 */ 43 struct IatAddrTab 44 { 45 DWORD dwCallAddr;//以便區分當前是什麼型別下使用了這個IAT地址 注意,這裡為整個呼叫程式碼的位置,而非呼叫的程式碼的函式地址的位置 46 BYTE bType;//該呼叫型別 0-7為mov eax、edx、esp、esi、ecx、ebx、ebp、edi 8為call 9為jmp (其中8和9可以歸類成一個處理方式) 10為push 47 DWORD dwRelocAddr;//用於新增到重定位塊中,該位置存放的為基址 48 WORD wIndex;//當前IAT位於載入表的下標 每個地址佔4位元組 49 DWORD dwOldIatAddr;//原IAT地址 50 DWORD dwNewIatAddr;//將要替換成的新IAT地址 51 DWORD dwJmpAddr;//shellcode所在的起始位置RVA 52 }; 53 vector<IatAddrTab>g_tagIAT;//存放IAT替換地址的結構體,成員為IAT地址,以及一個呼叫地址位置,還有一個該IAT型別 54 55 56 vector<DWORD>g_IATaddrList; 57 58 struct tagRelocation 59 { 60 DWORD wR_Head; 61 vector<WORD>wR_Offset; 62 }; 63 vector<tagRelocation>vOldReloction; 64 65 66 VOID GetKernel32Base(X86Assembler &a) 67 { 68 Label GetInfoBegin = a.newLabel(); 69 Label cmpDllName = a.newLabel(); 70 Label cmpChar = a.newLabel(); 71 Label GetNextModule = a.newLabel(); 72 Label GetBaseOver = a.newLabel(); 73 74 a.push(ebx); 75 a.push(ecx); 76 a.push(edx); 77 a.push(esi); 78 a.push(edi); 79 a.mov(edx, esp); 80 a.sub(esp, 0x18); 81 82 a.mov(dword_ptr(esp, 0x00), 0x0065006B); 83 a.mov(dword_ptr(esp, 0x04), 0x006E0072); 84 a.mov(dword_ptr(esp, 0x08), 0x006C0065); 85 a.mov(dword_ptr(esp, 0x0C), 0x00320033); 86 a.mov(dword_ptr(esp, 0x10), 0x0064002E); 87 a.mov(dword_ptr(esp, 0x14), 0x006C006C); 88 a.xor_(eax, eax); 89 a.mov(esi, dword_ptr_abs(0x30).setSegment(fs));//獲得PEB 同理mov esi,fs:[30] 90 a.mov(esi, dword_ptr(esi, 0x0C)); //取到dll的列表指標 91 a.mov(esi, dword_ptr(esi, 0x1C)); //取到初始化序模組化 92 93 a.bind(GetInfoBegin);//遍歷模組資訊 94 a.mov(edi, dword_ptr(esi, 8));//取到當前模組基址 95 a.lea(ebx, dword_ptr(esi, 0x1c));//取到UNICODE STRING結構 96 a.movzx(ecx, word_ptr(ebx));//取出長度 97 a.cmp (ecx, 24);//對比長度 98 a.jne(GetNextModule);//不等則獲取下一個模組 99 a.mov(ebx, dword_ptr(ebx , 4));//取到字串地址 此時ebx不再為結構地址 100 a.mov(ecx, 0);//用於遍歷 101 102 a.bind(cmpDllName);//對比模組名字 103 a.cmp(ecx, 24); 104 //遍歷到字元末尾 找到目標模組(先對的長度再對的字元,排除了前面同名後面A/W的情況) 105 a.jnl(GetBaseOver);//獲取基址結束 106 a.xor_ (eax, eax);//清空容器 107 a.movzx(eax, word_ptr(ebx, ecx)); 108 a.cmp(eax, 0x41);//如果是大寫字元(41~5A)範圍內,轉成小寫 109 a.jna(cmpChar); 110 a.cmp(eax, 0x5A); 111 a.ja(cmpChar); 112 a.add(eax, 0x20);//大寫字元的值+0x20即轉成小寫字元 113 114 a.bind(cmpChar);//對比每個字元 115 a.cmp(ax, word_ptr(esp, ecx));//對比字串內容 116 a.jne(GetNextModule);//不等則獲取下一個模組 117 a.add(ecx, 2); 118 a.jmp(cmpDllName); 119 120 a.bind(GetNextModule);//獲得下一個模組資訊 121 a.mov(esi, dword_ptr(esi));//取得下一個初始化模組 122 a.test(esi, esi); 123 a.jnz(GetInfoBegin);//不為空則繼續遍歷 124 125 a.bind(GetBaseOver); 126 a.mov(eax, edi); 127 a.add(esp, 0x18); 128 a.pop(edi); 129 a.pop(esi); 130 a.pop(edx); 131 a.pop(ecx); 132 a.pop(ebx); 133 } 134 135 VOID GetLoadLibraryAAddr(X86Assembler &a) 136 { 137 //跳轉標記 138 Label FindFuncAddr = a.newLabel(); 139 Label FindFuncAddrOver = a.newLabel(); 140 141 a.push(ebx); 142 a.push(ecx); 143 a.push(esi); 144 a.push(ebp); 145 //記得開始獲取出來的都是RVA 要加上DLL的基址edi來取值 146 a.mov(eax, dword_ptr(edi, 0x3c)); 147 a.mov(ebx, dword_ptr(edi, eax, 0, 0x78));//NT頭+0x78 = 匯入表RVA 148 //上面等價於[edi + eax + 0x78],如果沒有0的話,他會把第三個引數當成2的N次方變成了edi + eax * 2的0x78次方 149 a.add(ebx, edi);//ebx=匯入表 150 a.mov(ecx, dword_ptr(ebx, 0x18));//ecx=按名稱匯出個數 151 a.mov(esi, dword_ptr(ebx, 0x20));//esi=匯出函式名稱表rva 152 a.add(esi, edi); 153 154 a.bind(FindFuncAddr); 155 a.sub(ecx, 1);//從後面往前遍歷 能少佔用一個暫存器,但要記得先-1再遍歷 156 a.jz(FindFuncAddrOver);//減到0即遍歷完 157 a.mov(ebp, dword_ptr(esi, ecx, 2));//取到函式名稱比拗最後一個函式名的RVA 等價於[esi,ecx*(2的n次方)] 158 a.add(ebp, edi); 159 a.cmp(dword_ptr(ebp), 0x64616F4C); 160 a.jne(FindFuncAddr); 161 a.cmp(dword_ptr(ebp, 4), 0x7262694C); 162 a.jne(FindFuncAddr); 163 a.cmp(dword_ptr(ebp, 8), 0x41797261); 164 a.jne(FindFuncAddr); 165 a.cmp(byte_ptr(ebp, 12), 0);//結束符 防止類似LoadLibrary和LoadLibraryA擴充套件函式名偏差出現 166 a.jne(FindFuncAddr); 167 //此時ecx為遍歷的下標 168 a.mov(esi, dword_ptr(ebx, 0x24));//esi=匯出函式序號表RVA(上面名稱對比完 回收esi) 169 a.add(esi, edi); 170 a.movzx(ebp, word_ptr(esi, ecx, 1));//ebp=函式序號 ebp=[esi+ecx*2一次方] 171 //EBP:Get=2b0 Load=3c2 172 a.mov(esi, dword_ptr(ebx, 0x1c));//esi=函式地址表RVA 173 a.add(esi, edi); 174 a.mov(eax, dword_ptr(esi, ebp, 2));//地址=地址表+序號*2的2次方 175 a.add(eax, edi); 176 //此時eax為loadlibraryA地址 177 a.bind(FindFuncAddrOver); 178 a.pop(ebp); 179 a.pop(esi); 180 a.pop(ecx); 181 a.pop(ebx); 182 } 183 184 VOID GetGetProcAddressAddr(X86Assembler &a) 185 { 186 //跳轉標記 187 Label FindFuncAddr = a.newLabel(); 188 Label FindFuncAddrOver = a.newLabel(); 189 190 a.push(ebx); 191 a.push(ecx); 192 a.push(esi); 193 a.push(ebp); 194 //記得開始獲取出來的都是RVA 要加上DLL的基址edi來取值 195 a.mov(eax, dword_ptr(edi, 0x3c)); 196 a.mov(ebx, dword_ptr(edi, eax, 0, 0x78));//NT頭+0x78 = 匯入表RVA 197 //上面等價於[edi + eax + 0x78],如果沒有0的話,他會把第三個引數當成2的N次方變成了edi + eax * 2的0x78次方 198 a.add(ebx, edi);//ebx=匯入表 199 a.mov(ecx, dword_ptr(ebx, 0x18));//ecx=按名稱匯出個數 200 a.mov(esi, dword_ptr(ebx, 0x20));//esi=匯出函式名稱表rva 201 a.add(esi, edi); 202 203 a.bind(FindFuncAddr); 204 a.sub(ecx, 1);//從後面往前遍歷 能少佔用一個暫存器,但要記得先-1再遍歷 205 a.jz(FindFuncAddrOver);//減到0即遍歷完 206 a.mov(ebp, dword_ptr(esi, ecx, 2));//取到函式名稱比拗最後一個函式名的RVA 等價於[esi,ecx*(2的n次方)] 207 a.add(ebp, edi); 208 a.cmp(dword_ptr(ebp), 0x50746547); 209 a.jne(FindFuncAddr); 210 a.cmp(dword_ptr(ebp, 4), 0x41636f72); 211 a.jne(FindFuncAddr); 212 a.cmp(dword_ptr(ebp, 8), 0x65726464); 213 a.jne(FindFuncAddr); 214 a.cmp(word_ptr(ebp, 12), 0x7373); 215 a.jne(FindFuncAddr); 216 a.cmp(byte_ptr(ebp, 14), 0);//結束符 防止類似LoadLibrary和LoadLibraryA擴充套件函式名偏差出現 217 a.jne(FindFuncAddr); 218 219 //此時ecx為遍歷的下標 220 a.mov(esi, dword_ptr(ebx, 0x24));//esi=匯出函式序號表RVA(上面名稱對比完 回收esi) 221 a.add(esi, edi); 222 a.movzx(ebp, word_ptr(esi, ecx, 1));//ebp=函式序號 ebp=[esi+ecx*2一次方] 223 //EBP:Get=2b0 Load=3c2 224 a.mov(esi, dword_ptr(ebx, 0x1c));//esi=函式地址表RVA 225 a.add(esi, edi); 226 a.mov(eax, dword_ptr(esi, ebp, 2));//地址=地址表+序號*2的2次方 227 a.add(eax, edi); 228 //此時eax為loadlibraryA地址 229 a.bind(FindFuncAddrOver); 230 a.pop(ebp); 231 a.pop(esi); 232 a.pop(ecx); 233 a.pop(ebx); 234 } 235 DWORD RVAtoFA(DWORD dwRVA) //RVA轉檔案地址 236 { 237 PIMAGE_DOS_HEADER pDosHead = PIMAGE_DOS_HEADER(g_pFileSrc); 238 PIMAGE_NT_HEADERS pNtHead = PIMAGE_NT_HEADERS((DWORD)pDosHead + pDosHead->e_lfanew); 239 PIMAGE_SECTION_HEADER pSection = (PIMAGE_SECTION_HEADER)(pNtHead->FileHeader.SizeOfOptionalHeader + (DWORD)&pNtHead->OptionalHeader); 240 int iSectionNum = pNtHead->FileHeader.NumberOfSections; 241 242 for (int i = 0; i < iSectionNum; i++) 243 { 244 if (dwRVA >= pSection->VirtualAddress && dwRVA < (pSection->VirtualAddress + pSection->Misc.VirtualSize)) 245 { 246 return (DWORD)g_pFileSrc + dwRVA - pSection->VirtualAddress + pSection->PointerToRawData; 247 } 248 pSection++; 249 } 250 return 0; //轉換失敗 251 } 252 253 DWORD FAtoRVA(DWORD dwFA) //檔案地址轉RVA 254 { 255 PIMAGE_DOS_HEADER pDosHead = PIMAGE_DOS_HEADER(g_pFileSrc); 256 PIMAGE_NT_HEADERS pNtHead = PIMAGE_NT_HEADERS((DWORD)pDosHead + pDosHead->e_lfanew); 257 PIMAGE_SECTION_HEADER pSection = (PIMAGE_SECTION_HEADER)(pNtHead->FileHeader.SizeOfOptionalHeader + (DWORD)&pNtHead->OptionalHeader); 258 int iSectionNum = pNtHead->FileHeader.NumberOfSections; 259 260 for (int i = 0; i < iSectionNum; i++) 261 { 262 if (dwFA >= pSection->PointerToRawData && dwFA < (pSection->PointerToRawData + pSection->SizeOfRawData)) 263 { 264 return (DWORD)dwFA - pSection->PointerToRawData + pSection->VirtualAddress; 265 } 266 pSection++; 267 } 268 return 0; //轉換失敗 269 } 270 271 272 BOOL LoadFile(char *pFileName) //獲取檔案內容 273 { 274 HANDLE hFile = CreateFileA(pFileName, 275 GENERIC_READ, 276 FILE_SHARE_READ, 277 NULL, 278 OPEN_EXISTING, 279 FILE_ATTRIBUTE_NORMAL, 280 0); 281 if (!hFile) 282 { 283 return false; 284 } 285 g_iFileSize = GetFileSize(hFile, NULL); 286 287 g_pFileSrc = (UCHAR*)malloc(g_iFileSize); 288 if (!g_pFileSrc) 289 { 290 cout << "申請記憶體失敗" << endl; 291 return false; 292 } 293 294 if (!ReadFile(hFile, g_pFileSrc, g_iFileSize, NULL, NULL)) 295 { 296 cout << "讀取檔案失敗" << endl; 297 return false; 298 } 299 300 return true; 301 } 302 303 304 BOOL CheckPE() //檢查PE檔案格式 305 { 306 PIMAGE_DOS_HEADER pDosHead = PIMAGE_DOS_HEADER(g_pFileSrc); 307 PIMAGE_NT_HEADERS pNtHead = PIMAGE_NT_HEADERS((DWORD)pDosHead + pDosHead->e_lfanew); 308 if (pDosHead->e_magic != 0x5a4d || pNtHead->Signature != 0x4550) 309 { 310 return false; 311 } 312 g_iImageBase = pNtHead->OptionalHeader.ImageBase; 313 g_iFileAlignment = pNtHead->OptionalHeader.FileAlignment; 314 g_iSectionAlignment = pNtHead->OptionalHeader.SectionAlignment; 315 g_iOldOEP = pNtHead->OptionalHeader.AddressOfEntryPoint; 316 return true; 317 } 318 319 320 321 BOOL FindCodeAddr() //找到呼叫了IAT中的地址的程式碼位置 322 { 323 PIMAGE_DOS_HEADER pDosHead = (PIMAGE_DOS_HEADER)g_pFileSrc; 324 PIMAGE_NT_HEADERS pNtHead = (PIMAGE_NT_HEADERS)((DWORD)pDosHead + pDosHead->e_lfanew); 325 if (!pNtHead->OptionalHeader.DataDirectory[1].VirtualAddress) 326 { 327 return false; 328 } 329 330 PIMAGE_IMPORT_DESCRIPTOR pImpotrList = (PIMAGE_IMPORT_DESCRIPTOR)RVAtoFA(pNtHead->OptionalHeader.DataDirectory[1].VirtualAddress); //IAT 331 while (pImpotrList->FirstThunk)//獲得該程式的IAT地址 332 { 333 int i = 0; 334 while (1) 335 { 336 DWORD iIatAddr = *(DWORD*)RVAtoFA(pImpotrList->FirstThunk + i * sizeof(DWORD)); 337 if (!iIatAddr) 338 { 339 break; 340 } 341 DWORD dwIatAddr = pImpotrList->FirstThunk + i * sizeof(DWORD); 342 g_IATaddrList.push_back(dwIatAddr); 343 i++; 344 } 345 pImpotrList++; 346 } 347 348 349 //獲取呼叫這些IAT地址的程式碼地址 350 for (int i = 0; i < g_iFileSize - 5; i++) 351 { 352 //mov eax 353 if (g_pFileSrc[i] == 0xA1) 354 { 355 DWORD IatAddr = *(DWORD*)(g_pFileSrc + i + 1); 356 for (int iNum = 0; iNum < g_IATaddrList.size(); iNum++) 357 { 358 if (g_IATaddrList[iNum] == (IatAddr^g_iImageBase)) 359 { 360 IatAddrTab IatInfo; 361 IatInfo.dwCallAddr = FAtoRVA(i); 362 IatInfo.bType = 0; 363 IatInfo.wIndex = iNum; 364 IatInfo.dwOldIatAddr = g_IATaddrList[iNum]; 365 g_tagIAT.push_back(IatInfo); 366 i += 4; //for迴圈會加1,操作符+地址共5位元組 367 continue; 368 } 369 } 370 } 371 372 //mov edx、esp、esi、ecx、ebx、ebp、edi 373 if (g_pFileSrc[i] == 0x8B && (g_pFileSrc[i + 1] == 0x15 || g_pFileSrc[i + 1] == 0x25 || g_pFileSrc[i + 1] == 0x35 || 374 g_pFileSrc[i + 1] == 0x0D || g_pFileSrc[i + 1] == 0x1D || g_pFileSrc[i + 1] == 0x2D || g_pFileSrc[i + 1] == 0x3D)) 375 { 376 DWORD IatAddr = *(DWORD*)(g_pFileSrc + i + 2); 377 for (int iNum = 0; iNum < g_IATaddrList.size(); iNum++) 378 { 379 if (g_IATaddrList[iNum] == (IatAddr^g_iImageBase)) 380 { 381 DWORD ddddd = FAtoRVA(i); 382 if (g_pFileSrc[i + 1] == 0x15) //edx 383 { 384 IatAddrTab IatInfo; 385 IatInfo.dwCallAddr = FAtoRVA(i); 386 IatInfo.bType = 1; 387 IatInfo.wIndex = iNum; 388 IatInfo.dwOldIatAddr = g_IATaddrList[iNum]; 389 g_tagIAT.push_back(IatInfo); 390 } 391 else if (g_pFileSrc[i + 1] == 0x25) //esp 392 { 393 IatAddrTab IatInfo; 394 IatInfo.dwCallAddr = FAtoRVA(i); 395 IatInfo.bType = 2; 396 IatInfo.wIndex = iNum; 397 IatInfo.dwOldIatAddr = g_IATaddrList[iNum]; 398 g_tagIAT.push_back(IatInfo); 399 } 400 else if (g_pFileSrc[i + 1] == 0x35) //esi 401 { 402 IatAddrTab IatInfo; 403 IatInfo.dwCallAddr = FAtoRVA(i); 404 IatInfo.bType = 3; 405 IatInfo.wIndex = iNum; 406 IatInfo.dwOldIatAddr = g_IATaddrList[iNum]; 407 g_tagIAT.push_back(IatInfo); 408 } 409 else if (g_pFileSrc[i + 1] == 0x0D) //ecx 410 { 411 IatAddrTab IatInfo; 412 IatInfo.dwCallAddr = FAtoRVA(i); 413 IatInfo.bType = 4; 414 IatInfo.wIndex = iNum; 415 IatInfo.dwOldIatAddr = g_IATaddrList[iNum]; 416 g_tagIAT.push_back(IatInfo); 417 } 418 else if (g_pFileSrc[i + 1] == 0x1D) //ebx 419 { 420 IatAddrTab IatInfo; 421 IatInfo.dwCallAddr = FAtoRVA(i); 422 IatInfo.bType = 5; 423 IatInfo.wIndex = iNum; 424 IatInfo.dwOldIatAddr = g_IATaddrList[iNum]; 425 g_tagIAT.push_back(IatInfo); 426 } 427 else if (g_pFileSrc[i + 1] == 0x2D) //ebp 428 { 429 IatAddrTab IatInfo; 430 IatInfo.dwCallAddr = FAtoRVA(i); 431 IatInfo.bType = 6; 432 IatInfo.wIndex = iNum; 433 IatInfo.dwOldIatAddr = g_IATaddrList[iNum]; 434 g_tagIAT.push_back(IatInfo); 435 } 436 else if (g_pFileSrc[i + 1] == 0x3D) //edi 437 { 438 IatAddrTab IatInfo; 439 IatInfo.dwCallAddr = FAtoRVA(i); 440 IatInfo.bType = 7; 441 IatInfo.wIndex = iNum; 442 IatInfo.dwOldIatAddr = g_IATaddrList[iNum]; 443 g_tagIAT.push_back(IatInfo); 444 } 445 i += 5; //for迴圈會加1,操作符+地址共6位元組 446 continue; 447 } 448 } 449 } 450 451 //call jmp push 452 if (g_pFileSrc[i] == 0xFF && (g_pFileSrc[i + 1] == 0x15 || g_pFileSrc[i + 1] == 0x25 || g_pFileSrc[i + 1] == 0x35)) 453 { 454 DWORD IatAddr = *(DWORD*)(g_pFileSrc + i + 2); 455 for (int iNum = 0; iNum < g_IATaddrList.size(); iNum++) 456 { 457 if (g_IATaddrList[iNum] == (IatAddr^g_iImageBase)) 458 { 459 DWORD ddddd = FAtoRVA(i); 460 if (g_pFileSrc[i + 1] == 0x15) //call 461 { 462 IatAddrTab IatInfo; 463 IatInfo.dwCallAddr = FAtoRVA(i); 464 IatInfo.bType = 8; 465 IatInfo.wIndex = iNum; 466 IatInfo.dwOldIatAddr = g_IATaddrList[iNum]; 467 g_tagIAT.push_back(IatInfo); 468 } 469 else if (g_pFileSrc[i + 1] == 0x25) //jmp 470 { 471 IatAddrTab IatInfo; 472 IatInfo.dwCallAddr = FAtoRVA(i); 473 IatInfo.bType = 9; 474 IatInfo.wIndex = iNum; 475 IatInfo.dwOldIatAddr = g_IATaddrList[iNum]; 476 g_tagIAT.push_back(IatInfo); 477 } 478 else if (g_pFileSrc[i + 1] == 0x35) //push 479 { 480 IatAddrTab IatInfo; 481 IatInfo.dwCallAddr = FAtoRVA(i); 482 IatInfo.bType = 10; 483 IatInfo.wIndex = iNum; 484 IatInfo.dwOldIatAddr = g_IATaddrList[iNum]; 485 g_tagIAT.push_back(IatInfo); 486 } 487 i += 5; //for迴圈會加1,操作符+地址共6位元組 488 continue; 489 } 490 } 491 } 492 } 493 494 return true; 495 } 496 497 498 bool SaveDll() //儲存DLL相關資料 499 { 500 PIMAGE_DOS_HEADER pDosHead = (PIMAGE_DOS_HEADER)g_pFileSrc; 501 PIMAGE_NT_HEADERS pNtHead = (PIMAGE_NT_HEADERS)((DWORD)pDosHead + pDosHead->e_lfanew); 502 DWORD dwImportRVA = pNtHead->OptionalHeader.DataDirectory[1].VirtualAddress; 503 PIMAGE_IMPORT_DESCRIPTOR pImport = (PIMAGE_IMPORT_DESCRIPTOR)RVAtoFA(dwImportRVA); 504 while (pImport->FirstThunk) 505 { 506 DLLFuncTag tagDllList;//Dll資訊結構 507 508 char *szDllName = (char*)RVAtoFA(pImport->Name); 509 int iDllNameLen = strlen(szDllName) + 1; 510 char *szNewDllName = (char*)malloc(iDllNameLen); 511 memcpy(szNewDllName, szDllName, iDllNameLen); 512 513 tagDllList.szDllName = szNewDllName; 514 tagDllList.bDllNameLenth = iDllNameLen; 515 516 PIMAGE_THUNK_DATA pIAT = (PIMAGE_THUNK_DATA)RVAtoFA(pImport->FirstThunk); 517 while (pIAT->u1.Function) 518 { 519 FuncTag tagFuncInfo;//函式資訊結構 520 DWORD dwFuncAddr = pIAT->u1.Function; 521 if (dwFuncAddr & 0x80000000) 522 { 523 tagDllList.bTab = 0;//按序號匯入 524 tagFuncInfo.iFuncNameLenth = 4; 525 tagFuncInfo.szFuncName = (char*)(dwFuncAddr ^ 0x80000000); 526 tagDllList.vFuncNAMEorNo.push_back(tagFuncInfo); 527 } 528 else 529 { 530 tagDllList.bTab = 1;//按名稱匯入 531 PIMAGE_IMPORT_BY_NAME pFunc = (PIMAGE_IMPORT_BY_NAME)RVAtoFA(pIAT->u1.Function); 532 int iFuncNameLen = strlen(pFunc->Name) + 1; 533 char *szFuncName = (char*)malloc(iFuncNameLen); 534 memcpy(szFuncName, pFunc->Name, iFuncNameLen); 535 tagFuncInfo.iFuncNameLenth = iFuncNameLen; 536 tagFuncInfo.szFuncName = szFuncName; 537 tagDllList.vFuncNAMEorNo.push_back(tagFuncInfo); 538 } 539 pIAT++; 540 } 541 tagDllList.wFuncNum = tagDllList.vFuncNAMEorNo.size(); 542 g_tagDllFunc.push_back(tagDllList); 543 pImport++; 544 } 545 546 //將IAT表資訊隱藏(每個DLL只有一個匯入函式) 547 PIMAGE_IMPORT_DESCRIPTOR pImpotrList = (PIMAGE_IMPORT_DESCRIPTOR)RVAtoFA(pNtHead->OptionalHeader.DataDirectory[1].VirtualAddress); 548 while (pImpotrList->FirstThunk) 549 { 550 PIMAGE_THUNK_DATA pIAT = (PIMAGE_THUNK_DATA)RVAtoFA(pImpotrList->FirstThunk); 551 PIMAGE_THUNK_DATA pINT = (PIMAGE_THUNK_DATA)RVAtoFA(pImpotrList->OriginalFirstThunk); 552 pIAT++;//保留第一個 553 pINT++; 554 while (pIAT->u1.Function)//將IAT清空 555 { 556 pIAT->u1.Function = 0; 557 pIAT++; 558 } 559 while (pINT->u1.Function)//將INT清空 560 { 561 pINT->u1.Function = 0; 562 pINT++; 563 } 564 pImpotrList++; 565 } 566 return true; 567 } 568 569 570 571 572 bool NewIat() 573 { 574 PIMAGE_DOS_HEADER pDosHead = (PIMAGE_DOS_HEADER)g_pFileSrc; 575 PIMAGE_NT_HEADERS pNtHead = (PIMAGE_NT_HEADERS)((DWORD)pDosHead + pDosHead->e_lfanew); 576 PIMAGE_SECTION_HEADER pSection = (PIMAGE_SECTION_HEADER)((DWORD)&pNtHead->OptionalHeader + pNtHead->FileHeader.SizeOfOptionalHeader); 577 for (int i = 0; i < pNtHead->FileHeader.NumberOfSections; i++) 578 { 579 //將每個節都改為可寫屬性,以便在後續修改。 580 //本來只修改.text節的屬性即可,但由於該節的位置不在data陣列裡面記錄,單憑節名判斷未必準確,所以將所以節都改為可寫- 581 pSection->Characteristics += 0x80000000; 582 } 583 if (!(pNtHead->OptionalHeader.DataDirectory[5].VirtualAddress))//噹噹前程式沒有重定位表 584 { 585 PIMAGE_SECTION_HEADER pSection = (PIMAGE_SECTION_HEADER)((DWORD)&pNtHead->OptionalHeader + pNtHead->FileHeader.SizeOfOptionalHeader); 586 pSection += pNtHead->FileHeader.NumberOfSections - 1; 587 int iNewSectionFileAddr = pSection->PointerToRawData + pSection->SizeOfRawData; 588 int iNewSectionFileMapAddr = 0; 589 if (!(pSection->Misc.VirtualSize % g_iSectionAlignment)) 590 { 591 iNewSectionFileMapAddr = pSection->VirtualAddress + pSection->Misc.VirtualSize; 592 } 593 else 594 { 595 iNewSectionFileMapAddr = pSection->VirtualAddress + pSection->Misc.VirtualSize 596 + g_iSectionAlignment - (pSection->Misc.VirtualSize % g_iSectionAlignment); 597 } 598 599 pSection++; 600 memcpy(pSection->Name, ".KD", 3); 601 pSection->VirtualAddress = iNewSectionFileMapAddr; 602 pSection->PointerToRawData = iNewSectionFileAddr; 603 pSection->Characteristics = (0x20000000 | 0x40000000 | 0x80000000 | 0x40); //節屬性 可讀可寫可執行已被初始化 604 pNtHead->FileHeader.NumberOfSections += 1;//節表數量+1 605 606 607 //將IAT的資料壓入新節中資料排列分別為DLL數量(2位元組)、DLL名字長度、該 608 int iAddIatLenth = 0;//已經增加的iat資料長度 609 //先新增2位元組資料說明該程式的DLL數量 610 g_pFileSrc = (UCHAR*)realloc(g_pFileSrc, g_iFileSize + iAddIatLenth + 1); 611 byte bDllNum = g_tagDllFunc.size(); 612 memcpy(g_pFileSrc + g_iFileSize + iAddIatLenth, &bDllNum, 1); 613 iAddIatLenth += 2; 614 for (int i = 0; i < bDllNum; i++) 615 { 616 //新增DLL名長度 617 int bDllNameLenth = g_tagDllFunc[i].bDllNameLenth; 618 g_pFileSrc = (UCHAR*)realloc(g_pFileSrc, g_iFileSize + iAddIatLenth + 2); 619 memcpy(g_pFileSrc + g_iFileSize + iAddIatLenth, &bDllNameLenth, 2); 620 iAddIatLenth += 2; 621 622 //新增DLL名 623 g_pFileSrc = (UCHAR*)realloc(g_pFileSrc, g_iFileSize + iAddIatLenth + bDllNameLenth); 624 memcpy(g_pFileSrc + g_iFileSize + iAddIatLenth, g_tagDllFunc[i].szDllName, bDllNameLenth); 625 iAddIatLenth += bDllNameLenth; 626 627 //新增該DLL中的匯入函式數量 方便後續遍歷 628 g_pFileSrc = (UCHAR*)realloc(g_pFileSrc, g_iFileSize + iAddIatLenth + 4); 629 memcpy(g_pFileSrc + g_iFileSize + iAddIatLenth, (DWORD*)&g_tagDllFunc[i].wFuncNum, 4); 630 iAddIatLenth += 4; 631 632 //新增該DLL的匯入方式 0為序號1為名稱 633 g_pFileSrc = (UCHAR*)realloc(g_pFileSrc, g_iFileSize + iAddIatLenth + 1); 634 memcpy(g_pFileSrc + g_iFileSize + iAddIatLenth, (byte*)&g_tagDllFunc[i].bTab, 1); 635 iAddIatLenth += 1; 636 for (int j = 0; j < g_tagDllFunc[i].wFuncNum; j++) 637 { 638 //新增函式名或序號 639 if (!(g_tagDllFunc[i].bTab)) //序號 640 { 641 g_pFileSrc = (UCHAR*)realloc(g_pFileSrc, g_iFileSize + iAddIatLenth + 6);//2長度4序號 642 memcpy(g_pFileSrc + g_iFileSize + iAddIatLenth, (WORD*)&g_tagDllFunc[i].vFuncNAMEorNo[j].iFuncNameLenth, 2); 643 iAddIatLenth += 2; 644 memcpy(g_pFileSrc + g_iFileSize + iAddIatLenth, (DWORD*)&g_tagDllFunc[i].vFuncNAMEorNo[j].szFuncName, 4); 645 iAddIatLenth += 4; 646 } 647 else //名字 648 { 649 int iFuncNameLenth = g_tagDllFunc[i].vFuncNAMEorNo[j].iFuncNameLenth;//長度 650 g_pFileSrc = (UCHAR*)realloc(g_pFileSrc, g_iFileSize + iAddIatLenth + 2 + iFuncNameLenth);//前2位元組存放長度 後面為函式名稱 651 memcpy(g_pFileSrc + g_iFileSize + iAddIatLenth, (WORD*)&iFuncNameLenth, 2); 652 iAddIatLenth += 2; 653 memcpy(g_pFileSrc + g_iFileSize + iAddIatLenth, g_tagDllFunc[i].vFuncNAMEorNo[j].szFuncName, iFuncNameLenth); 654 iAddIatLenth += iFuncNameLenth; 655 } 656 } 657 } 658 659 //獲取新的OEP並修改舊的OEP 660 g_iNewOEP = iNewSectionFileMapAddr + iAddIatLenth;//新節的 661 pDosHead = (PIMAGE_DOS_HEADER)g_pFileSrc; 662 pNtHead = (PIMAGE_NT_HEADERS)((DWORD)pDosHead + pDosHead->e_lfanew); 663 pNtHead->OptionalHeader.AddressOfEntryPoint = g_iNewOEP; 664 665 JitRuntime _x86RunTimeObject; 666 X86Assembler a(&_x86RunTimeObject); 667 668 //當程式沒有重定位表時,根據call 0000 0000來獲得程式基址,有重定位表時則根據重定位表 669 char szGetOEP[] = { 0xE8, 0x00, 0x00, 0x00, 0x00 }; //同理jit.call(0x00000000); 670 a.pop(eax); 671 a.sub(eax, 5);//此時得到oep所在的地址 oep距離基址隔著 672 a.sub(eax, g_iNewOEP);//OEP所在的基址-偏移 得到基址 673 a.mov(ebp, eax); //儲存程式基址到ebp 674 a.add(eax, g_iOldOEP); 675 a.jmp(eax); 676 677 PVOID szJit = a.make(); 678 int iJitLenth = a.getCodeSize() + 5; //包括e8 0000 0000; 679 680 g_pFileSrc = (UCHAR*)realloc(g_pFileSrc, g_iFileSize + iAddIatLenth + iJitLenth); 681 memcpy(g_pFileSrc + g_iFileSize + iAddIatLenth, szGetOEP, 5); 682 memcpy(g_pFileSrc + g_iFileSize + iAddIatLenth + 5, szJit, iJitLenth); 683 684 int iAddSrcLen = iAddIatLenth + iJitLenth;//一共增加的程式碼 685 //完善節長度等資料 保守起見重新獲取節表資訊 686 pDosHead = (PIMAGE_DOS_HEADER)g_pFileSrc; 687 pNtHead = (PIMAGE_NT_HEADERS)((DWORD)pDosHead + pDosHead->e_lfanew); 688 pSection = (PIMAGE_SECTION_HEADER)((DWORD)&pNtHead->OptionalHeader + pNtHead->FileHeader.SizeOfOptionalHeader); 689 pSection += pNtHead->FileHeader.NumberOfSections - 1; 690 if (!(iAddSrcLen%g_iFileAlignment)) 691 { 692 pSection->SizeOfRawData = iAddSrcLen; 693 } 694 else 695 { 696 pSection->SizeOfRawData = iAddSrcLen + g_iFileAlignment - (iAddSrcLen%g_iFileAlignment); 697 } 698 if (!(iAddSrcLen%g_iSectionAlignment)) 699 { 700 pSection->Misc.VirtualSize = iAddSrcLen; 701 } 702 else 703 { 704 pSection->Misc.VirtualSize = iAddSrcLen + g_iSectionAlignment - (iAddSrcLen%g_iSectionAlignment); 705 } 706 pNtHead->OptionalHeader.SizeOfImage += pSection->Misc.VirtualSize; 707 708 if (iAddSrcLen != pSection->SizeOfRawData)//當新增長度與對齊後的節長度不相等時,將其補全 709 { 710 int iLenth = pSection->SizeOfRawData;//先儲存,以免擴容後原地址被回收 711 //g_pFileSrc = (UCHAR*)realloc(g_pFileSrc, g_iFileSize + iLenth); 712 UCHAR *uuu = (UCHAR*)malloc(g_iFileSize + iAddSrcLen); 713 memcpy(uuu, g_pFileSrc, g_iFileSize + iAddSrcLen); 714 g_pFileSrc = (UCHAR*)malloc(g_iFileSize + iLenth); 715 memcpy(g_pFileSrc, uuu, g_iFileSize + iAddSrcLen); 716 memset(g_pFileSrc + g_iFileSize + iAddSrcLen, 0, iLenth - iAddSrcLen); 717 } 718 g_iFileSize += pSection->SizeOfRawData; 719 } 720 721 722 723 ///////////////////////////////////////////////////////////////////////////// 724 //當有重定位表時,先儲存相關資料,刪除重定位表,新增節,再在後面還原重定位表 725 else 726 { 727 //把重定位表資料移動到新節當中 728 //獲取位置和長度 729 int iRelocationAddr = pNtHead->OptionalHeader.DataDirectory[5].VirtualAddress; 730 int iRelocationLenth = pNtHead->OptionalHeader.DataDirectory[5].Size;//資料長度 731 char *szR_Src = (char*)malloc(iRelocationLenth); 732 memcpy(szR_Src, (char*)RVAtoFA(iRelocationAddr), iRelocationLenth); 733 734 PIMAGE_SECTION_HEADER pSection = (PIMAGE_SECTION_HEADER)((DWORD)&pNtHead->OptionalHeader + pNtHead->FileHeader.SizeOfOptionalHeader); 735 char szR_Name[8] = { 0 }; 736 int iR_MapLenth = 0;//節中對映長度 737 int iR_FileLenth = 0;//節中檔案長度 738 while (1) 739 { 740 if (pSection->VirtualAddress == iRelocationAddr) //定位到重定位表節表 741 { 742 strcpy(szR_Name, (char*)pSection->Name); 743 iR_MapLenth = pSection->Misc.VirtualSize; 744 iR_FileLenth = pSection->SizeOfRawData; 745 break; 746 } 747 pSection++; 748 } 749 750 //刪除重定位表相關資訊 751 memset(g_pFileSrc + g_iFileSize - iR_FileLenth, 0, iR_FileLenth);//把重定位表資料用0覆蓋 752 memset(pSection, 0, sizeof(IMAGE_SECTION_HEADER)); 753 pNtHead->FileHeader.NumberOfSections--; 754 //調整檔案記憶體大小 755 int iAlignmentSize = iR_MapLenth % g_iSectionAlignment; 756 if (!iAlignmentSize) 757 { 758 pNtHead->OptionalHeader.SizeOfImage -= iR_MapLenth; //調整檔案記憶體大小 759 } 760 else 761 { 762 pNtHead->OptionalHeader.SizeOfImage = 763 pNtHead->OptionalHeader.SizeOfImage 764 - (iR_MapLenth - iAlignmentSize + g_iSectionAlignment); 765 } 766 g_iFileSize -= iR_FileLenth; 767 768 769 //新增節 770 pSection = (PIMAGE_SECTION_HEADER)((DWORD)&pNtHead->OptionalHeader + pNtHead->FileHeader.SizeOfOptionalHeader); 771 pSection += pNtHead->FileHeader.NumberOfSections - 1; 772 int iNewSectionFileAddr = pSection->PointerToRawData + pSection->SizeOfRawData; 773 int iNewSectionFileMapAddr = 0; 774 if (!(pSection->Misc.VirtualSize % g_iSectionAlignment)) 775 { 776 iNewSectionFileMapAddr = pSection->VirtualAddress + pSection->Misc.VirtualSize; 777 } 778 else 779 { 780 iNewSectionFileMapAddr = pSection->VirtualAddress + pSection->Misc.VirtualSize 781 + g_iSectionAlignment - (pSection->Misc.VirtualSize % g_iSectionAlignment); 782 } 783 784 pSection++; 785 memcpy(pSection->Name, ".KD", 3); 786 pSection->VirtualAddress = iNewSectionFileMapAddr; 787 pSection->PointerToRawData = iNewSectionFileAddr; 788 pSection->Characteristics = (0x20000000 | 0x40000000 | 0x80000000 | 0x40); //節屬性 可讀可寫可執行已被初始化 789 pNtHead->FileHeader.NumberOfSections += 1;//節表數量+1 790 791 792 //將IAT的資料壓入新節中資料排列分別為DLL數量(2位元組)、DLL名字長度、該 793 int iAddIatLenth = 0;//已經增加的iat資料長度 794 //先新增1位元組資料說明該程式的DLL數量 795 g_pFileSrc = (UCHAR*)realloc(g_pFileSrc, g_iFileSize + iAddIatLenth + 1); 796 byte bDllNum = g_tagDllFunc.size(); 797 memcpy(g_pFileSrc + g_iFileSize + iAddIatLenth, &bDllNum, 1); 798 iAddIatLenth += 1; 799 for (int i = 0; i < bDllNum; i++) 800 { 801 //新增DLL名長度 802 byte bDllNameLenth = g_tagDllFunc[i].bDllNameLenth; 803 g_pFileSrc = (UCHAR*)realloc(g_pFileSrc, g_iFileSize + iAddIatLenth + 1); 804 memcpy(g_pFileSrc + g_iFileSize + iAddIatLenth, &bDllNameLenth, 1); 805 iAddIatLenth += 1; 806 807 //新增DLL名 808 g_pFileSrc = (UCHAR*)realloc(g_pFileSrc, g_iFileSize + iAddIatLenth + bDllNameLenth); 809 memcpy(g_pFileSrc + g_iFileSize + iAddIatLenth, g_tagDllFunc[i].szDllName, bDllNameLenth); 810 iAddIatLenth += bDllNameLenth; 811 812 //新增該DLL中的匯入函式數量 方便後續遍歷 813 g_pFileSrc = (UCHAR*)realloc(g_pFileSrc, g_iFileSize + iAddIatLenth + 2); 814 memcpy(g_pFileSrc + g_iFileSize + iAddIatLenth, (DWORD*)&g_tagDllFunc[i].wFuncNum, 2); 815 iAddIatLenth += 2; 816 817 //新增該DLL的匯入方式 0為序號1為名稱 818 g_pFileSrc = (UCHAR*)realloc(g_pFileSrc, g_iFileSize + iAddIatLenth + 1); 819 memcpy(g_pFileSrc + g_iFileSize + iAddIatLenth, (byte*)&g_tagDllFunc[i].bTab, 1); 820 iAddIatLenth += 1; 821 for (int j = 0; j < g_tagDllFunc[i].wFuncNum; j++) 822 { 823 //新增函式名或序號 824 if (!(g_tagDllFunc[i].bTab)) //序號 825 { 826 g_pFileSrc = (UCHAR*)realloc(g_pFileSrc, g_iFileSize + iAddIatLenth + 5);//1長度4序號 827 memcpy(g_pFileSrc + g_iFileSize + iAddIatLenth, (BYTE*)&g_tagDllFunc[i].vFuncNAMEorNo[j].iFuncNameLenth, 1); 828 iAddIatLenth += 1; 829 memcpy(g_pFileSrc + g_iFileSize + iAddIatLenth, (DWORD*)&g_tagDllFunc[i].vFuncNAMEorNo[j].szFuncName, 4); 830 iAddIatLenth += 4; 831 } 832 else //名字 833 { 834 int iFuncNameLenth = g_tagDllFunc[i].vFuncNAMEorNo[j].iFuncNameLenth;//長度 835 g_pFileSrc = (UCHAR*)realloc(g_pFileSrc, g_iFileSize + iAddIatLenth + 1 + iFuncNameLenth);//前2位元組存放長度 後面為函式名稱 836 memcpy(g_pFileSrc + g_iFileSize + iAddIatLenth, (BYTE*)&iFuncNameLenth, 1); 837 iAddIatLenth += 1; 838 memcpy(g_pFileSrc + g_iFileSize + iAddIatLenth, g_tagDllFunc[i].vFuncNAMEorNo[j].szFuncName, iFuncNameLenth); 839 iAddIatLenth += iFuncNameLenth; 840 } 841 } 842 } 843 844 //存放載入的函式地址表的RVA 845 int iLoadAddressTabRVA = iNewSectionFileMapAddr + iAddIatLenth; 846 int iLoadIatLenth = g_IATaddrList.size() * 4;//用於存放載入的函式地址表長度 此處多4位元組來存放基址 847 848 849 //獲取新的OEP並修改舊的OEP 850 g_iNewOEP = iNewSectionFileMapAddr + iAddIatLenth + iLoadIatLenth; 851 pDosHead = (PIMAGE_DOS_HEADER)g_pFileSrc; 852 pNtHead = (PIMAGE_NT_HEADERS)((DWORD)pDosHead + pDosHead->e_lfanew); 853 pNtHead->OptionalHeader.AddressOfEntryPoint = g_iNewOEP; 854 855 JitRuntime _x86RunTimeObject; 856 X86Assembler a(&_x86RunTimeObject); 857 858 //跳轉標記 859 Label LoadDllBegin = a.newLabel(); 860 Label LoadDllOver = a.newLabel(); 861 862 Label NameExport = a.newLabel(); 863 Label NameExportBegin = a.newLabel(); 864 Label NameExportOver = a.newLabel(); 865 Label NoExportBegin = a.newLabel(); 866 Label NoExportOver = a.newLabel(); 867 868 //test 869 Label lTest = a.newLabel(); 870 871 //當有重定位表時,將NewOEP+1新增到重定位項中,重定位後的地址-OldOEP即可得到新的基址 872 //這裡push g_iOldOEP + g_iImageBase而不是g_iImageBase(直接得到新基址 不用再-舊OEP),是因為push完還要ret到舊OEP 873 //執行完這段後,棧上是舊OEP的地址,ebx是程式基址 874 a.push(g_iOldOEP + g_iImageBase); 875 a.mov(ebx, dword_ptr(esp)); 876 a.sub(ebx, g_iOldOEP); 877 878 /*a.call(lTest); 879 a.bind(lTest); 880 a.pop(eax);*/ 881 882 a.pusha(); 883 a.push(ebx);//將程式基址儲存到棧上 884 a.sub(esp, 0x8); 885 a.mov(ebp, esp); //ebp從上往下分別是LoadLibraryA函式地址、GetProcAddress函式地址和程式基址 ebp-4為Dll基址 -8為填充函式載入地址起始地址 886 a.sub(esp, 0x8); 887 888 GetKernel32Base(a); 889 a.mov(edi, eax);//edi為所遍歷到的DLL基址 890 891 //計算函式地址 892 GetLoadLibraryAAddr(a); 893 a.mov(dword_ptr(ebp, 0), eax);//儲存LoadLibraryA的值到棧上 894 GetGetProcAddressAddr(a); 895 a.mov(dword_ptr(ebp, 4), eax);//儲存GetProcAddress的值到棧上 896 a.mov(eax, iLoadAddressTabRVA); 897 a.add(eax, dword_ptr(ebp, 8));//填充函式地址RVA+程式基址 898 a.mov(dword_ptr(ebp, -8), eax);//放到ebp-8的地址上 899 900 901 //開始遍歷IAT資料,填充函式載入地址表 902 a.mov(esi, iNewSectionFileMapAddr); 903 a.add(esi, dword_ptr(ebp, 8));//esi為IAT資料起點 904 a.mov(ebx, 1);//以ebx開始遍歷 達到長度 退出 905 906 907 //載入DLL 908 a.bind(LoadDllBegin); 909 a.cmp(ebx, iAddIatLenth);//如果遍歷長度大於等於IAT資料長度 910 a.jnl(LoadDllOver); 911 a.movzx(ecx, byte_ptr(esi, ebx));//取得DLL名長度 912 a.add(ebx, 1);//+Dll名長度的變數1 913 a.lea(eax, dword_ptr(esi,ebx));//獲得函式名地址 914 a.push(eax); 915 a.add(ebx, ecx);//+DLL名長度 916 a.mov(eax, dword_ptr(ebp));//獲得loadlibrary地址 917 a.call(eax); 918 a.mov(dword_ptr(ebp,-4),eax);//ebp為load.. +4為get.. +8為程式基址 -4為當前Dll基址 -8為填充函式載入地址位置 919 a.movzx(edi, word_ptr(esi, ebx));//取出該DLL匯出函式數量 920 a.add(ebx, 2); 921 a.movzx(edx, byte_ptr(esi, ebx));//取出匯出方式 922 a.add(ebx, 1); 923 a.cmp(edx, 1);//為1時,名稱匯出 924 a.je(NameExportBegin); 925 926 927 //序號匯出 928 a.bind(NoExportBegin);//序號匯出迴圈起點 929 a.cmp(edi, 0); 930 a.je(NoExportOver); 931 a.add(ebx, 1); 932 a.mov(eax, dword_ptr(esi, ebx));//取得序號 933 a.add(ebx, 4); 934 a.push(eax); 935 a.push(dword_ptr(ebp, -4)); 936 a.mov(eax, dword_ptr(ebp, 4));//獲得GetProcAddress 937 a.call(eax); 938 a.mov(edx, dword_ptr(ebp, -8));//取得裝載函式表 939 a.mov(dword_ptr(edx), eax); 940 a.add(dword_ptr(ebp, -8), 4);//裝載函式表RVA+4 941 a.sub(edi, 1); 942 a.jmp(NoExportBegin); 943 a.bind(NoExportOver);//序號匯出迴圈終點 944 a.jmp(LoadDllBegin); //重新載入新DLL 945 946 //名稱匯出 947 a.bind(NameExportBegin);//名稱匯出迴圈起點 948 a.cmp(edi, 0); 949 a.je(NameExportOver); 950 a.movzx(ecx, byte_ptr(esi, ebx));//取得名稱長度 951 a.add(ebx, 1); 952 a.lea(eax, dword_ptr(esi, ebx));//名稱地址 953 a.push(eax); 954 a.add(ebx, ecx); 955 a.push(dword_ptr(ebp, -4)); 956 a.mov(eax, dword_ptr(ebp, 4)); 957 a.call(eax); 958 a.mov(edx, dword_ptr(ebp, -8));//取得裝載函式表 959 a.mov(dword_ptr(edx), eax); 960 a.add(dword_ptr(ebp, -8), 4);//裝載函式表RVA+4 961 a.sub(edi, 1); 962 a.jmp(NameExportBegin); 963 a.bind(NameExportOver);//名稱匯出迴圈終點 964 a.jmp(LoadDllBegin); //重新載入新DLL 965 966 967 968 ///////////開始構造替換呼叫程式碼的shellcode////////////// 969 //注意esp為當前操作的棧頂 ebp+8為程式所在基址 970 int iNewJitBeginAddrRva = iNewSectionFileMapAddr + iAddIatLenth + iLoadIatLenth; //替換的shellcode開始的地址 971 int iNewJitLenth = a.getCodeSize(); 972 for (int i = 0; i < g_tagIAT.size(); i++) 973 { 974 if (g_tagIAT[i].bType == 0) //EAX 975 { 976 g_tagIAT[i].dwNewIatAddr = iNewSectionFileMapAddr + iAddIatLenth + g_tagIAT[i].wIndex * 4; 977 a.push(ebx); 978 a.push(ebx); 979 a.push(ebx); 980 a.push(esi); 981 a.mov(ebx, (int)g_tagIAT[i].dwCallAddr + 5); 982 a.mov(esi, g_iImageBase);//程式基址 後續會將這個位置新增到重定位塊處,執行時即變為程式基址了 983 g_tagIAT[i].dwRelocAddr = iNewJitBeginAddrRva + a.getCodeSize() - 4;//shellcode開始的位置+當前jit長度 再往回4位元組 即為存放基址的位置 984 a.lea(ebx, dword_ptr(ebx, esi)); 985 a.mov(dword_ptr(esp, 0xC), ebx);//當前指令所在RVA+5+程式基址 =返回地址 986 a.mov(ebx, (int)g_tagIAT[i].dwNewIatAddr); 987 a.lea(ebx, dword_ptr(ebx, esi)); 988 a.mov(ebx, dword_ptr(ebx)); 989 a.mov(dword_ptr(esp, 0x8), ebx);//代替原函式地址的地址 990 a.pop(esi); 991 a.pop(ebx); 992 a.pop(eax); 993 a.ret(); 994 g_tagIAT[i].dwJmpAddr = iNewJitBeginAddrRva + iNewJitLenth; 995 iNewJitLenth = a.getCodeSize(); 996 } 997 else if (g_tagIAT[i].bType == 1) //EDX 998 { 999 g_tagIAT[i].dwNewIatAddr = iNewSectionFileMapAddr + iAddIatLenth + g_tagIAT[i].wIndex * 4; 1000 a.push(ebx); 1001 a.push(ebx); 1002 a.push(ebx); 1003 a.push(esi); 1004 a.mov(ebx, (int)g_tagIAT[i].dwCallAddr + 6); 1005 a.mov(esi, g_iImageBase);//程式基址 後續會將這個位置新增到重定位塊處,執行時即變為程式基址了 1006 g_tagIAT[i].dwRelocAddr = iNewJitBeginAddrRva + a.getCodeSize() - 4;//shellcode開始的位置+當前jit長度 再往回4位元組 即為存放基址的位置 1007 a.lea(ebx, dword_ptr(ebx, esi)); 1008 a.mov(dword_ptr(esp, 0xC), ebx);//當前指令所在RVA+5+程式基址 =返回地址 1009 a.mov(ebx, (int)g_tagIAT[i].dwNewIatAddr); 1010 a.lea(ebx, dword_ptr(ebx, esi)); 1011 a.mov(ebx, dword_ptr(ebx)); 1012 a.mov(dword_ptr(esp, 0x8), ebx);//代替原函式地址的地址 1013 a.pop(esi); 1014 a.pop(ebx); 1015 a.pop(edx); 1016 a.ret(); 1017 g_tagIAT[i].dwJmpAddr = iNewJitBeginAddrRva + iNewJitLenth; 1018 iNewJitLenth = a.getCodeSize(); 1019 } 1020 else if (g_tagIAT[i].bType == 2) //ESP 1021 { 1022 g_tagIAT[i].dwNewIatAddr = iNewSectionFileMapAddr + iAddIatLenth + g_tagIAT[i].wIndex * 4; 1023 a.push(ebx); 1024 a.push(ebx); 1025 a.push(ebx); 1026 a.push(esi); 1027 a.mov(ebx, (int)g_tagIAT[i].dwCallAddr + 6); 1028 a.mov(esi, g_iImageBase);//程式基址 後續會將這個位置新增到重定位塊處,執行時即變為程式基址了 1029 g_tagIAT[i].dwRelocAddr = iNewJitBeginAddrRva + a.getCodeSize() - 4;//shellcode開始的位置+當前jit長度 再往回4位元組 即為存放基址的位置 1030 a.lea(ebx, dword_ptr(ebx, esi)); 1031 a.mov(dword_ptr(esp, 0xC), ebx);//當前指令所在RVA+6+程式基址 =返回地址 1032 a.mov(ebx, (int)g_tagIAT[i].dwNewIatAddr); 1033 a.lea(ebx, dword_ptr(ebx, esi)); 1034 a.mov(ebx, dword_ptr(ebx)); 1035 a.mov(dword_ptr(esp, 0x8), ebx);//代替原函式地址的地址 1036 a.pop(esi); 1037 a.pop(ebx); 1038 a.pop(esp); 1039 a.ret(); 1040 g_tagIAT[i].dwJmpAddr = iNewJitBeginAddrRva + iNewJitLenth; 1041 iNewJitLenth = a.getCodeSize(); 1042 } 1043 else if (g_tagIAT[i].bType == 3) //ESI 1044 { 1045 g_tagIAT[i].dwNewIatAddr = iNewSectionFileMapAddr + iAddIatLenth + g_tagIAT[i].wIndex * 4; 1046 a.push(ebx); 1047 a.push(ebx); 1048 a.push(ebx); 1049 a.push(esi); 1050 a.mov(ebx, (int)g_tagIAT[i].dwNewIatAddr); 1051 a.mov(esi, g_iImageBase);//程式基址 後續會將這個位置新增到重定位塊處,執行時即變為程式基址了 1052 g_tagIAT[i].dwRelocAddr = iNewJitBeginAddrRva + a.getCodeSize() - 4;//shellcode開始的位置+當前jit長度 再往回4位元組 即為存放基址的位置 1053 a.lea(ebx, dword_ptr(ebx, esi)); 1054 a.mov(ebx, dword_ptr(ebx)); 1055 a.mov(dword_ptr(esp, 0x8), ebx);//代替原函式地址的地址 1056 a.mov(ebx, (int)g_tagIAT[i].dwCallAddr + 6); 1057 a.lea(ebx, dword_ptr(ebx, esi)); 1058 a.mov(dword_ptr(esp, 0xC), ebx);//當前指令所在RVA+6+程式基址 =返回地址 1059 a.pop(esi); 1060 a.pop(ebx); 1061 a.pop(esi); 1062 a.ret(); 1063 g_tagIAT[i].dwJmpAddr = iNewJitBeginAddrRva + iNewJitLenth; 1064 iNewJitLenth = a.getCodeSize(); 1065 } 1066 else if (g_tagIAT[i].bType == 4) //ECX 1067 { 1068 g_tagIAT[i].dwNewIatAddr = iNewSectionFileMapAddr + iAddIatLenth + g_tagIAT[i].wIndex * 4; 1069 a.push(ebx); 1070 a.push(ebx); 1071 a.push(ebx); 1072 a.push(esi); 1073 a.mov(ebx, (int)g_tagIAT[i].dwCallAddr + 6); 1074 a.mov(esi, g_iImageBase);//程式基址 後續會將這個位置新增到重定位塊處,執行時即變為程式基址了 1075 g_tagIAT[i].dwRelocAddr = iNewJitBeginAddrRva + a.getCodeSize() - 4;//shellcode開始的位置+當前jit長度 再往回4位元組 即為存放基址的位置 1076 a.lea(ebx, dword_ptr(ebx, esi)); 1077 a.mov(dword_ptr(esp, 0xC), ebx);//當前指令所在RVA+6+程式基址 =返回地址 1078 a.mov(ebx, (int)g_tagIAT[i].dwNewIatAddr); 1079 a.lea(ebx, dword_ptr(ebx, esi)); 1080 a.mov(ebx, dword_ptr(ebx)); 1081 a.mov(dword_ptr(esp, 0x8), ebx);//代替原函式地址的地址 1082 a.pop(esi); 1083 a.pop(ebx); 1084 a.pop(ecx); 1085 a.ret(); 1086 g_tagIAT[i].dwJmpAddr = iNewJitBeginAddrRva + iNewJitLenth; 1087 iNewJitLenth = a.getCodeSize(); 1088 } 1089 else if (g_tagIAT[i].bType == 5) //EBX 1090 { 1091 g_tagIAT[i].dwNewIatAddr = iNewSectionFileMapAddr + iAddIatLenth + g_tagIAT[i].wIndex * 4; 1092 a.push(ebx); 1093 a.push(ebx); 1094 a.push(ebx); 1095 a.push(esi); 1096 a.mov(ebx, (int)g_tagIAT[i].dwCallAddr + 6); 1097 a.mov(esi, g_iImageBase);//程式基址 後續會將這個位置新增到重定位塊處,執行時即變為程式基址了 1098 g_tagIAT[i].dwRelocAddr = iNewJitBeginAddrRva + a.getCodeSize() - 4;//shellcode開始的位置+當前jit長度 再往回4位元組 即為存放基址的位置 1099 a.lea(ebx, dword_ptr(ebx, esi)); 1100 a.mov(dword_ptr(esp, 0xC), ebx);//當前指令所在RVA+6+程式基址 =返回地址 1101 a.mov(ebx, (int)g_tagIAT[i].dwNewIatAddr); 1102 a.lea(ebx, dword_ptr(ebx, esi)); 1103 a.mov(ebx, dword_ptr(ebx)); 1104 a.mov(dword_ptr(esp, 0x8), ebx);//代替原函式地址的地址 1105 a.pop(esi); 1106 a.pop(ebx); 1107 a.pop(ebx); 1108 a.ret(); 1109 g_tagIAT[i].dwJmpAddr = iNewJitBeginAddrRva + iNewJitLenth; 1110 iNewJitLenth = a.getCodeSize(); 1111 } 1112 else if (g_tagIAT[i].bType == 6) //EBP 1113 { 1114 g_tagIAT[i].dwNewIatAddr = iNewSectionFileMapAddr + iAddIatLenth + g_tagIAT[i].wIndex * 4; 1115 a.push(ebx); 1116 a.push(ebx); 1117 a.push(ebx); 1118 a.push(esi); 1119 a.mov(ebx, (int)g_tagIAT[i].dwCallAddr + 6); 1120 a.mov(esi, g_iImageBase);//程式基址 後續會將這個位置新增到重定位塊處,執行時即變為程式基址了 1121 g_tagIAT[i].dwRelocAddr = iNewJitBeginAddrRva + a.getCodeSize() - 4;//shellcode開始的位置+當前jit長度 再往回4位元組 即為存放基址的位置 1122 a.lea(ebx, dword_ptr(ebx, esi)); 1123 a.mov(dword_ptr(esp, 0xC), ebx);//當前指令所在RVA+6+程式基址 =返回地址 1124 a.mov(ebx, (int)g_tagIAT[i].dwNewIatAddr); 1125 a.lea(ebx, dword_ptr(ebx, esi)); 1126 a.mov(ebx, dword_ptr(ebx)); 1127 a.mov(dword_ptr(esp, 0x8), ebx);//代替原函式地址的地址 1128 a.pop(esi); 1129 a.pop(ebx); 1130 a.pop(ebp); 1131 a.ret(); 1132 g_tagIAT[i].dwJmpAddr = iNewJitBeginAddrRva + iNewJitLenth; 1133 iNewJitLenth = a.getCodeSize(); 1134 } 1135 else if (g_tagIAT[i].bType == 7) //EDI 1136 { 1137 g_tagIAT[i].dwNewIatAddr = iNewSectionFileMapAddr + iAddIatLenth + g_tagIAT[i].wIndex * 4; 1138 a.push(ebx); 1139 a.push(ebx); 1140 a.push(ebx); 1141 a.push(esi); 1142 a.mov(ebx, (int)g_tagIAT[i].dwCallAddr + 6); 1143 a.mov(esi, g_iImageBase);//程式基址 後續會將這個位置新增到重定位塊處,執行時即變為程式基址了 1144 g_tagIAT[i].dwRelocAddr = iNewJitBeginAddrRva + a.getCodeSize() - 4;//shellcode開始的位置+當前jit長度 再往回4位元組 即為存放基址的位置 1145 a.lea(ebx, dword_ptr(ebx, esi)); 1146 a.mov(dword_ptr(esp, 0xC), ebx);//當前指令所在RVA+6+程式基址 =返回地址 1147 a.mov(ebx, (int)g_tagIAT[i].dwNewIatAddr); 1148 a.lea(ebx, dword_ptr(ebx, esi)); 1149 a.mov(ebx, dword_ptr(ebx)); 1150 a.mov(dword_ptr(esp, 0x8), ebx);//代替原函式地址的地址 1151 a.pop(esi); 1152 a.pop(ebx); 1153 a.pop(edi); 1154 a.ret(); 1155 g_tagIAT[i].dwJmpAddr = iNewJitBeginAddrRva + iNewJitLenth; 1156 iNewJitLenth = a.getCodeSize(); 1157 } 1158 else if (g_tagIAT[i].bType == 8) //Call 1159 { 1160 g_tagIAT[i].dwNewIatAddr = iNewSectionFileMapAddr + iAddIatLenth + g_tagIAT[i].wIndex * 4; 1161 a.push(ebx); 1162 a.push(ebx); 1163 a.push(ebx); 1164 a.push(esi); 1165 a.mov(ebx, (int)g_tagIAT[i].dwNewIatAddr); 1166 a.mov(esi, g_iImageBase);//程式基址 後續會將這個位置新增到重定位塊處,執行時即變為程式基址了 1167 g_tagIAT[i].dwRelocAddr = iNewJitBeginAddrRva + a.getCodeSize() - 4;//shellcode開始的位置+當前jit長度 再往回4位元組 即為存放基址的位置 1168 a.lea(ebx, dword_ptr(ebx, esi)); 1169 a.mov(ebx, dword_ptr(ebx)); 1170 a.mov(dword_ptr(esp, 8), ebx);//存放目標函式地址的地址的RVA 1171 a.mov(ebx, (int)g_tagIAT[i].dwCallAddr + 6);//返回地址RVA 1172 a.lea(ebx, dword_ptr(ebx, esi)); 1173 a.mov(dword_ptr(esp, 0xC), ebx); 1174 a.pop(esi); 1175 a.pop(ebx); 1176 a.ret(); 1177 g_tagIAT[i].dwJmpAddr = iNewJitBeginAddrRva + iNewJitLenth; 1178 iNewJitLenth = a.getCodeSize(); 1179 } 1180 else if (g_tagIAT[i].bType == 9) //JMP 1181 { 1182 g_tagIAT[i].dwNewIatAddr = iNewSectionFileMapAddr + iAddIatLenth + g_tagIAT[i].wIndex * 4; 1183 a.push(ebx); 1184 a.push(ebx); 1185 a.push(ebx); 1186 a.push(esi); 1187 a.mov(ebx, (int)g_tagIAT[i].dwNewIatAddr); 1188 a.mov(esi, g_iImageBase);//程式基址 後續會將這個位置新增到重定位塊處,執行時即變為程式基址了 1189 g_tagIAT[i].dwRelocAddr = iNewJitBeginAddrRva + a.getCodeSize() - 4;//shellcode開始的位置+當前jit長度 再往回4位元組 即為存放基址的位置 1190 a.lea(ebx, dword_ptr(ebx, esi)); 1191 a.mov(dword_ptr(esp,4), 0x3535);//填充垃圾資料 1192 a.mov(ebx, dword_ptr(ebx)); 1193 a.mov(dword_ptr(esp, 0xC), ebx);//存放目標函式地址的地址的RVA 1194 a.pop(esi); 1195 a.pop(ebx); 1196 a.pop(ebx); 1197 a.ret(); 1198 g_tagIAT[i].dwJmpAddr = iNewJitBeginAddrRva + iNewJitLenth; 1199 iNewJitLenth = a.getCodeSize(); 1200 } 1201 else if (g_tagIAT[i].bType == 10) //PUSH 1202 { 1203 g_tagIAT[i].dwNewIatAddr = iNewSectionFileMapAddr + iAddIatLenth + g_tagIAT[i].wIndex * 4; 1204 a.push(ebx); 1205 a.push(ebx); 1206 a.push(ebx); 1207 a.push(esi); 1208 a.mov(ebx, (int)g_tagIAT[i].dwNewIatAddr); 1209 a.mov(esi, g_iImageBase);//程式基址 後續會將這個位置新增到重定位塊處,執行時即變為程式基址了 1210 g_tagIAT[i].dwRelocAddr = iNewJitBeginAddrRva + a.getCodeSize() - 4;//shellcode開始的位置+當前jit長度 再往回4位元組 即為存放基址的位置 1211 a.lea(ebx, dword_ptr(ebx, esi)); 1212 a.mov(ebx, dword_ptr(ebx)); 1213 a.mov(dword_ptr(esp, 0xC), ebx);//存放目標函式地址的地址的RVA 1214 a.mov(ebx, (int)g_tagIAT[i].dwCallAddr + 6); //返回地址RVA 1215 a.lea(ebx, dword_ptr(ebx, esi)); 1216 a.mov(dword_ptr(esp, 8), ebx); 1217 a.pop(esi); 1218 a.pop(ebx); 1219 a.ret(); 1220 g_tagIAT[i].dwJmpAddr = iNewJitBeginAddrRva + iNewJitLenth; 1221 iNewJitLenth = a.getCodeSize(); 1222 } 1223 } 1224 a.bind(LoadDllOver);//載入函式地址表以及構建替代IAT的ShellCode完成 1225 a.mov(edi, dword_ptr(ebp, 8));//獲得基址 1226 for (int i = 0; i < g_tagIAT.size(); i++) 1227 { 1228 a.lea(ecx, dword_ptr(edi, g_tagIAT[i].dwCallAddr)); 1229 a.mov(byte_ptr(ecx), 0xE9); 1230 //由於這裡的E9後面的值,是偏移,所以不用加上基址。偏移量=目標地址-當前指令地址-指令長度 1231 a.mov(dword_ptr(ecx, 1), (int)(g_tagIAT[i].dwJmpAddr - g_tagIAT[i].dwCallAddr - 5)); 1232 if (g_tagIAT[i].bType == 0) 1233 { 1234 continue; 1235 } 1236 a.mov(byte_ptr(ecx, 5), 0x90); 1237 } 1238 a.add(esp, 0x10);//8+8 1239 a.pop(ebx); 1240 a.popa(); 1241 a.ret(); 1242 1243 PVOID szJit = a.make(); 1244 int iJitLenth = a.getCodeSize(); 1245 g_pFileSrc = (UCHAR*)realloc(g_pFileSrc, g_iFileSize + iAddIatLenth + iLoadIatLenth + iJitLenth); 1246 memcpy(g_pFileSrc + g_iFileSize + iAddIatLenth + iLoadIatLenth , szJit, iJitLenth); 1247 1248 1249 //一共增加的程式碼=IAT相關資料+載入後的函式地址表大小+JIT程式碼長度 1250 int iAddSrcLen = iAddIatLenth + iLoadIatLenth + iJitLenth; 1251 //完善節長度等資料 保守起見重新獲取節表資訊 1252 pDosHead = (PIMAGE_DOS_HEADER)g_pFileSrc; 1253 pNtHead = (PIMAGE_NT_HEADERS)((DWORD)pDosHead + pDosHead->e_lfanew); 1254 pSection = (PIMAGE_SECTION_HEADER)((DWORD)&pNtHead->OptionalHeader + pNtHead->FileHeader.SizeOfOptionalHeader); 1255 pSection += pNtHead->FileHeader.NumberOfSections - 1; 1256 if (!(iAddSrcLen%g_iFileAlignment)) 1257 { 1258 pSection->SizeOfRawData = iAddSrcLen; 1259 } 1260 else 1261 { 1262 pSection->SizeOfRawData = iAddSrcLen + g_iFileAlignment - (iAddSrcLen%g_iFileAlignment); 1263 } 1264 if (!(iAddSrcLen%g_iSectionAlignment)) 1265 { 1266 pSection->Misc.VirtualSize = iAddSrcLen; 1267 } 1268 else 1269 { 1270 pSection->Misc.VirtualSize = iAddSrcLen + g_iSectionAlignment - (iAddSrcLen%g_iSectionAlignment); 1271 } 1272 pNtHead->OptionalHeader.SizeOfImage += pSection->Misc.VirtualSize; 1273 1274 if (iAddSrcLen != pSection->SizeOfRawData)//當新增長度與對齊後的節長度不相等時,將其補全 1275 { 1276 int iLenth = pSection->SizeOfRawData;//先儲存,以免擴容後原地址被回收 1277 g_pFileSrc = (UCHAR*)realloc(g_pFileSrc, g_iFileSize + iLenth); 1278 memset(g_pFileSrc + g_iFileSize + iAddSrcLen, 0, iLenth - iAddSrcLen); 1279 } 1280 g_iFileSize += pSection->SizeOfRawData; 1281 1282 1283 1284 //將原重定位中 涉及IAT的重定位項刪掉 1285 //1.先統計IAT中的地址位置程式碼(除了mov eax的地址位置在指令位置+1處,其他皆為+2) 1286 vector<WORD>vDeleteIatAddr;//需要刪除的重定位資訊 1287 for (int i = 0; i < g_tagIAT.size(); i++) 1288 { 1289 if (g_tagIAT[i].bType==0) //mov eax 重定位地址位於呼叫地址+1處 1290 { 1291 vDeleteIatAddr.push_back(g_tagIAT[i].dwCallAddr + 1); 1292 } 1293 else 1294 { 1295 vDeleteIatAddr.push_back(g_tagIAT[i].dwCallAddr + 2); 1296 } 1297 1298 } 1299 1300 //2.統計出重定位表有幾個重定位塊,每個塊的基址是多少,裡面有多少個偏移 1301 for (int i = 0; i < iRelocationLenth; i++) 1302 { 1303 tagRelocation addR; 1304 addR.wR_Head = *(int*)(szR_Src + i); 1305 int iR_Lenth = *(int*)(szR_Src + i + 4); 1306 for (int j = 8; j < iR_Lenth; j+=2) 1307 { 1308 WORD ccc = *(WORD*)(szR_Src + i + j); 1309 addR.wR_Offset.push_back(ccc); 1310 } 1311 vOldReloction.push_back(addR); 1312 i += iR_Lenth - 1; 1313 } 1314 1315 //3.根據IAT裡的地址,在重定位地址表查詢,找到之後將其刪除 1316 for (int i = 0; i < vDeleteIatAddr.size(); i++) 1317 { 1318 for (int j = 0; j < vOldReloction.size(); j++) 1319 { 1320 if ((vDeleteIatAddr[i] & 0xFFF000) > vOldReloction[j].wR_Head) //當呼叫地址的重定位塊大於當前重定位表塊時 1321 { 1322 continue; 1323 } 1324 else if ((vDeleteIatAddr[i] & 0xFFF000) < vOldReloction[j].wR_Head) 1325 { 1326 break; 1327 } 1328 else //找到對應重定位塊 1329 { 1330 for (int k = 0; k < vOldReloction[j].wR_Offset.size(); k++) 1331 { 1332 if ((vDeleteIatAddr[i] & 0xFFF) == (vOldReloction[j].wR_Offset[k] & 0xFFF)) 1333 { 1334 vOldReloction[j].wR_Offset.erase(vOldReloction[j].wR_Offset.begin() + k); 1335 goto NextIatAddr; 1336 } 1337 } 1338 } 1339 1340 } 1341 NextIatAddr:; 1342 } 1343 1344 //4.對齊重定位表資料, 1345 /*如果重定位塊中專案為偶數個,則跳過 1346 如果是奇數個,看最後一個是否為0。如果為0,刪掉;如果不為0,補0*/ 1347 for (int i = 0; i < vOldReloction.size(); i++) 1348 { 1349 int iReloctionNum = vOldReloction[i].wR_Offset.size(); 1350 if (iReloctionNum % 2) //取餘 如果能取到 說明為奇數 1351 { 1352 if (vOldReloction[i].wR_Offset[iReloctionNum-1] == 0) 1353 { 1354 vOldReloction[i].wR_Offset.pop_back(); 1355 } 1356 else 1357 { 1358 vOldReloction[i].wR_Offset.push_back(0); 1359 } 1360 } 1361 } 1362 1363 //恢復重定位表 1364 szR_Src = NULL; 1365 iRelocationLenth = 0; 1366 for (int i = 0; i < vOldReloction.size(); i++) 1367 { 1368 szR_Src = (char*)realloc(szR_Src, iRelocationLenth + 8); 1369 memcpy(szR_Src + iRelocationLenth, &vOldReloction[i].wR_Head, 4); 1370 int iR_Lenth = vOldReloction[i].wR_Offset.size() * 2 + 8; 1371 memcpy(szR_Src + iRelocationLenth + 4, &iR_Lenth, 4); 1372 iRelocationLenth += 8; 1373 for (int j = 0; j < vOldReloction[i].wR_Offset.size(); j++) 1374 { 1375 szR_Src = (char*)realloc(szR_Src, iRelocationLenth + 8 + j*2); 1376 memcpy(szR_Src + iRelocationLenth + j*2, &vOldReloction[i].wR_Offset[j], 2); 1377 } 1378 iRelocationLenth += vOldReloction[i].wR_Offset.size() * 2 ; 1379 } 1380 1381 1382 //增加新的重定位項 1383 char *szAddRelocSrc = NULL; //總新增重定位資料 1384 char *szNowAddrelocSrc = NULL;//子新增重定位資料 1385 int iAddRelocLen = 0; //總重定位資料長度 1386 int iNowAddRelocLen = 0; //子重定位資料長度 1387 1388 int iPage = 0; //頁大小 1389 int iPageOffset = 0; //頁內偏移 1390 1391 1392 //先增加新OEP用於求得基址的重定位項 1393 iNowAddRelocLen = 10; //子長度 1394 szNowAddrelocSrc = (char*)malloc(iNowAddRelocLen);//子資料 1395 iPage = (g_iNewOEP + 1) & 0xfff000; //PUSH 0000 0000 重定位資料為地址 偏移+1 1396 iPageOffset = ((g_iNewOEP + 1) & 0xfff) | 0x3000; 1397 memcpy(szNowAddrelocSrc, &iPage, 4);//頁偏移 1398 memcpy(szNowAddrelocSrc + 4, &iNowAddRelocLen, 4);//頁大小 1399 memcpy(szNowAddrelocSrc + 8, &iPageOffset, 2); 1400 1401 //開始新增shellcode中的重定位項 1402 for (int i = 0; i < g_tagIAT.size(); i++) 1403 { 1404 if (iPage == ((g_tagIAT[i].dwRelocAddr) & 0xfff000)) //判斷是否與當前頁大小一致 1405 { 1406 szNowAddrelocSrc = (char*)realloc(szNowAddrelocSrc, iNowAddRelocLen + 2); 1407 iPageOffset = (g_tagIAT[i].dwRelocAddr & 0xfff) | 0x3000; 1408 memcpy(szNowAddrelocSrc + iNowAddRelocLen, &iPageOffset, 2); 1409 iNowAddRelocLen += 2; 1410 memcpy(szNowAddrelocSrc + 4, &iNowAddRelocLen, 4);//頁大小 1411 } 1412 else //開啟新頁 1413 { 1414 if ((iNowAddRelocLen % 4)) //是否4位元組對齊 1415 { 1416 szNowAddrelocSrc = (char*)realloc(szNowAddrelocSrc, iNowAddRelocLen + 2); 1417 memset(szNowAddrelocSrc + iNowAddRelocLen, 0, 2); 1418 iNowAddRelocLen += 2; 1419 memcpy(szNowAddrelocSrc + 4, &iNowAddRelocLen, 4);//頁大小 1420 } 1421 1422 szAddRelocSrc = (char*)realloc(szAddRelocSrc, iAddRelocLen + iNowAddRelocLen);//將總重定位資料擴容 1423 memcpy(szAddRelocSrc + iAddRelocLen, szNowAddrelocSrc, iNowAddRelocLen); //複製子重定位塊到總重定位塊中 1424 iAddRelocLen += iNowAddRelocLen; //更新總重定位塊大小 1425 1426 iNowAddRelocLen = 10; 1427 szNowAddrelocSrc = (char*)malloc(iNowAddRelocLen);//子資料 1428 iPage = g_tagIAT[i].dwRelocAddr & 0xfff000; 1429 iPageOffset = (g_tagIAT[i].dwRelocAddr & 0xfff) | 0x3000; 1430 memcpy(szNowAddrelocSrc, &iPage, 4);//頁偏移 1431 memcpy(szNowAddrelocSrc + 4, &iNowAddRelocLen, 4);//頁大小 1432 memcpy(szNowAddrelocSrc + 8, &iPageOffset, 2); 1433 } 1434 } 1435 //此時 由於已經遍歷到tagIAT結構最後 但當前重定位塊併為新增到總重定位塊中,故需要再進行填充 1436 if ((iNowAddRelocLen % 4)) //是否4位元組對齊 1437 { 1438 szNowAddrelocSrc = (char*)realloc(szNowAddrelocSrc, iNowAddRelocLen + 2); 1439 memset(szNowAddrelocSrc + iNowAddRelocLen, 0, 2); 1440 iNowAddRelocLen += 2; 1441 memcpy(szNowAddrelocSrc + 4, &iNowAddRelocLen, 4);//頁大小 1442 } 1443 1444 szAddRelocSrc = (char*)realloc(szAddRelocSrc, iAddRelocLen + iNowAddRelocLen);//將總重定位資料擴容 1445 memcpy(szAddRelocSrc + iAddRelocLen, szNowAddrelocSrc, iNowAddRelocLen); //複製子重定位塊到總重定位塊中 1446 iAddRelocLen += iNowAddRelocLen; //更新總重定位塊大小 1447 1448 1449 if ((iR_FileLenth - iRelocationLenth) < iAddRelocLen) //節表長度和實際資料長度是否足夠填充新的重定位塊 1450 { 1451 //擴充重定位資料 1452 //整數取餘 = (新增資料總大小- 之前剩餘空間間隙)%對齊大小 1453 int iZeroLenth = (iAddRelocLen - (iR_FileLenth - iRelocationLenth)) % g_iFileAlignment; 1454 if (iZeroLenth) 1455 { 1456 iR_FileLenth = iRelocationLenth + iAddRelocLen + g_iFileAlignment - iZeroLenth; 1457 } 1458 else 1459 { 1460 iR_FileLenth = iRelocationLenth + iAddRelocLen; 1461 } 1462 szR_Src = (char*)realloc(szR_Src, iR_FileLenth); 1463 memcpy(szR_Src + iRelocationLenth, szAddRelocSrc, iAddRelocLen); 1464 memset(szR_Src + iRelocationLenth + iAddRelocLen, 0, iR_FileLenth - iRelocationLenth - iAddRelocLen); 1465 } 1466 else 1467 { 1468 szR_Src = (char*)realloc(szR_Src, iR_FileLenth); 1469 memcpy(szR_Src + iRelocationLenth, szAddRelocSrc, iAddRelocLen); 1470 iRelocationLenth += iAddRelocLen; 1471 memset(szR_Src + iRelocationLenth, 0, iR_FileLenth - iRelocationLenth); 1472 } 1473 1474 //還原重定位 1475 g_pFileSrc = (UCHAR*)realloc(g_pFileSrc, g_iFileSize + iR_FileLenth); 1476 memcpy(g_pFileSrc + g_iFileSize, szR_Src, iR_FileLenth); 1477 g_iFileSize += iR_FileLenth; 1478 1479 ////直接用realloc又抽風 用其他轉移吧 1480 //char *szCopyBuff = (char*)malloc(g_iFileSize + iR_FileLenth); 1481 //memcpy(szCopyBuff, g_pFileSrc, g_iFileSize); 1482 //memcpy(szCopyBuff + g_iFileSize, szR_Src, iR_FileLenth); 1483 //g_iFileSize += iR_FileLenth; 1484 //memcpy(g_pFileSrc, szCopyBuff, g_iFileSize); 1485 1486 1487 pDosHead = (PIMAGE_DOS_HEADER)g_pFileSrc; 1488 pNtHead = (PIMAGE_NT_HEADERS)((DWORD)pDosHead + pDosHead->e_lfanew); 1489 pSection = (PIMAGE_SECTION_HEADER)((DWORD)&pNtHead->OptionalHeader + pNtHead->FileHeader.SizeOfOptionalHeader); 1490 pSection += pNtHead->FileHeader.NumberOfSections - 1; 1491 int iR_FileAddr = pSection->PointerToRawData + pSection->SizeOfRawData; 1492 int iR_MapAddr = 0; 1493 if (!(pSection->Misc.VirtualSize % g_iSectionAlignment)) 1494 { 1495 iR_MapAddr = pSection->VirtualAddress + pSection->Misc.VirtualSize; 1496 } 1497 else 1498 { 1499 iR_MapAddr = pSection->VirtualAddress + pSection->Misc.VirtualSize 1500 + g_iSectionAlignment - (pSection->Misc.VirtualSize % g_iSectionAlignment); 1501 } 1502 1503 pSection++; 1504 strcpy((char*)pSection->Name, szR_Name); 1505 pSection->Characteristics = (0x20000000 | 0x40000000 | 0x80000000 | 0x40); 1506 pSection->VirtualAddress = iR_MapAddr; 1507 pSection->Misc.VirtualSize = iR_FileLenth; 1508 pSection->PointerToRawData = iR_FileAddr; 1509 pSection->SizeOfRawData = iR_FileLenth; 1510 pNtHead->OptionalHeader.DataDirectory[5].VirtualAddress = iR_MapAddr; 1511 pNtHead->OptionalHeader.DataDirectory[5].Size = iRelocationLenth; 1512 pNtHead->FileHeader.NumberOfSections += 1; 1513 if (!(iR_FileLenth%g_iSectionAlignment)) 1514 { 1515 pNtHead->OptionalHeader.SizeOfImage += iR_FileLenth; 1516 } 1517 else 1518 { 1519 pNtHead->OptionalHeader.SizeOfImage += iR_FileLenth + g_iSectionAlignment - (iR_FileLenth%g_iSectionAlignment); 1520 } 1521 1522 } 1523 return true; 1524 } 1525 1526 1527 1528 int main() 1529 { 1530 //"C:\\Users\\Admin\\Desktop\\彈窗.exe 1531 char FileName[] = { "C:\\Users\\Admin\\Desktop\\彈窗.exe" }; 1532 if (!LoadFile(FileName)) 1533 { 1534 cout << "檔案開啟失敗" << endl; 1535 system("pause"); 1536 return -1; 1537 } 1538 1539 if (!CheckPE()) 1540 { 1541 cout << "該程式不是PE檔案" << endl; 1542 system("pause"); 1543 return -1; 1544 } 1545 1546 if (!FindCodeAddr()) //找到對應呼叫IAT的地址 1547 { 1548 cout << "該程式沒有匯入表,請檢查" << endl; 1549 system("pause"); 1550 return -1; 1551 } 1552 1553 if (!SaveDll()) 1554 { 1555 cout << "儲存DLL資訊失敗" << endl; 1556 system("pause"); 1557 return -1; 1558 } 1559 1560 if (!NewIat()) 1561 { 1562 cout << "新建IAT表失敗" << endl; 1563 system("pause"); 1564 return -1; 1565 } 1566 1567 //C:\\Users\\Admin\\Desktop\\彈窗IAT加密測試.exe 1568 char NewFilePath[] = "C:\\Users\\Admin\\Desktop\\彈窗IAT加密測試.exe"; 1569 HANDLE hNewFile = CreateFileA(NewFilePath, 1570 GENERIC_READ | GENERIC_WRITE, 1571 FILE_SHARE_READ | FILE_SHARE_WRITE, 1572 NULL, 1573 CREATE_ALWAYS, //建立並覆蓋上一個檔案 1574 FILE_ATTRIBUTE_ARCHIVE, 1575 NULL); 1576 1577 if (hNewFile == INVALID_HANDLE_VALUE) 1578 { 1579 printf("檔案儲存失敗\n"); 1580 int iError = GetLastError(); 1581 return 1; 1582 } 1583 1584 LPDWORD iNum = NULL; 1585 WriteFile(hNewFile, g_pFileSrc, g_iFileSize, iNum, NULL); //寫入檔案 1586 CloseHandle(hNewFile); 1587 char *NewFileName1 = strrchr(NewFilePath, '\\') + 1; 1588 char *NewFileName = strtok(NewFileName1, "."); 1589 MessageBoxA(0, NewFileName, "加密成功", 0); 1590 MessageBoxA(0, "by:阿怪\n 2020.12.26", "IAT加密", 0); 1591 1592 system("pause"); 1593 }
IAT加密相對於程式碼段加密較為複雜,特別是在自己實現獲得函式地址,以及建立對應的shellcode,並把原呼叫指令全部一一修改的流程較為繁瑣,需要用到各種變數記錄位置。博主也是剛接觸到這塊的新手小白,如果有疑惑或者說的不對的地方歡迎在評論指出,互相學習。感謝!!