浅谈IAT加密原理及过程

上一次做完代码段加密后,又接触到了新的加密方式: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指令的代码,所以无法直接复制运行,这里仅提供编写思路。

浅谈IAT加密原理及过程
   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 }
View Code

 

IAT加密相对于代码段加密较为复杂,特别是在自己实现获得函数地址,以及创建对应的shellcode,并把原调用指令全部一一修改的流程较为繁琐,需要用到各种变量记录位置。博主也是刚接触到这块的新手小白,如果有疑惑或者说的不对的地方欢迎在评论指出,互相学习。感谢!!

上一篇:03 脱壳示例


下一篇:Mac os下安装pycurl