fly大侠在
外挂克星脱壳——江湖OnLine V1.05中秋版 
http://bbs.pediy.com/showthread.php?s=&threadid=17155
中说道
"看来作者对OllyDBD研究了不少,不过对SoftICE+IceExt却不作抵抗,可惜。"

主程序下载
http://www.szleyu.com/download/BSLYtools.zip

思路:
用SI 跟外挂克星主程序到oep, dump出来, 写1段小程序创建一个新的输入表
, 写1段小程序修正jmp走的IAT操作

开始

2ksp4+ds2.7+iceext


一   到oep

ep 是 2e1d0
bpmb 42e1d0 x
运行 断下

     42E1D0        CALL   [1000B194]        断下
     42E1D6        ADD    [EAX], AL
     42E1D8        ADD    [EAX], AL
     42E1DA        ADD    [EAX], AL
     42E1DC        ADD    [EAX], AL

bpmb 42e1d6 x
bpx.p readprocessmemory
ctrl-d 跑
第三次readprocessmemory断下后,F11返回
     
     9EE556        CALL   [KERNEL32!ReadProcessMemory]
     9EE55C        MOV    ESI, 009F7214    F11返回到这儿
     9EE561        LEA    EAX, [ESP+08]

清除readprocessmemory断点
F10走啊走啊走啊返回这个CALL到这儿

     9EFBC7        CALL   009EE3A0
     9EFBCC        TEST   EAX, EAX         到这儿
我这里EAX的返回值是0, 所以不行
r eax 改成 1

然后一路F10  断在ep的下一行42E1D6了
     42E1D0        CALL   [1000B194]
     42E1D6        JMP    40D8CA           断在这儿, 飞向光明之颠 



二   dump

基址400000 总大小40000
!dump \??\e:\1.bin 400000 40000

看到oep 开头几行有
40D8EB   PUSH  ESI
40D8EC   PUSH  EDI
40D8ED   MOV   [EBP-18], ESP
40D8F0   JMP   00CD145C    壳把调用API的地方偷走了
到CD145C向上看看,向下看看 发现一张表
     CD0048   E1 ED E6 77  FF 15 48 00  CD 00 E9 8D  9F 74 FF 00
     ......
     CD4708   00 92 9B 77  FF 15 08 47  CD 00 E9 1F  00 75 FF AA
反汇编一下CD0048处,意思就是
     CD004C   CALL [CD0048]   就是 CALL  77E6EDE1
     CD0052   JMP  00149FE4   跳回主代码段
这个表也要了
!dump \??\e:\api.bin cd0048 46d0

这时可以清除所有断点, si放掉后, 程序就跑起来了, 程序开在那里
一直会不断的MessageBox, 没办法,忍一下, 我们还要借原程序取输入表


三   修复 1.bin的PE格式

LordPE 打开1.bin
EntryPoint: 2E1D0 -> D8CA
.data  (30000, 7CC8, 30000, 4000)->(30000, 7CC8, 30000, 8000)
.rsrc  (38000, 71F8, 34000, 8000)->(38000, 71F8, 38000, 8000)
ImportTable(27004, 28) -> (0,0)
IAT(27000, 544) -> (0,0)

1.bin改名1.exe


四   输入表

先做一件事情, 任务管理器关掉Explorer.exe 再打开Explorer.exe, 这样别的进程就能看到它了
原来的IAT是(27000, 544), 借用这块地方

-----------------------------第一个程序---------------------------------
#include <windows.h>
#include <stdio.h>

void main(void)
{
  FILE *fp = fopen("e:\\api.bin", "rb");
  HANDLE h = OpenProcess(PROCESS_ALL_ACCESS, 0, 1360); // 打开外挂克星进程

  char apibuf[16];

  DWORD dwPrevApiAddr = 0;
  DWORD dwApiAddr = 0;
  DWORD dwIatAddr = 0x400000 + 0x27000;                // IAT地址
  DWORD dwWrite;
  
  int r = fread(apibuf, 16, 1, fp);
  while (r !=EOF && r != 0)
  {
    dwApiAddr = *(LPDWORD)apibuf;
    if (dwPrevApiAddr != dwApiAddr)
    {
      // 不带重复的一个个写进去
      WriteProcessMemory(h, (LPVOID)dwIatAddr, apibuf, 4, &dwWrite);
      dwIatAddr += 4;
    }
    dwPrevApiAddr = dwApiAddr;
    r = fread(apibuf, 16, 1, fp);
  }

  fclose(fp);
  CloseHandle(h);
}

写完后, 用ImportREC 打开外挂克星进程 RVA 27000, SIZE 514 
得到的指针就1个, 显示是假的, 别理它
ImportREC的选项 选中 "创建新的IAT", 去掉 "修复ep 到oep"
修复1.exe, 得到1_.exe



五   修正jmp走的IAT操作
可以关掉程序了
---------------------------第二个程序---------------------------------
#include <windows.h>
#include <stdio.h>

void main(void)
{

  FILE *fp = fopen("e:\\1_.exe", "rb");
  char *mapoffile = new char[0x42000];      //文件大小0x42000
  fread(mapoffile, 0x42000, 1, fp);         //文件内容全读进来
  fclose(fp);

  fp = fopen("e:\\api.bin", "rb");

  char apibuf[16];

  DWORD dwPrevApiAddr = 0;
  DWORD dwApiAddr = 0;
  DWORD dwIatAddr = 0x400000 + 0x40000;
  DWORD dwRCall;

  
  int r = fread(apibuf, 16, 1, fp);
  dwPrevApiAddr = *(LPDWORD)apibuf;
  while (r !=EOF && r != 0)
  {
    // 得到IAT的位置
    dwApiAddr = *(LPDWORD)apibuf;
    if (dwPrevApiAddr != dwApiAddr)
      dwIatAddr += 4;
    if (*(LPDWORD)(dwIatAddr-0x400000+mapoffile) == 0)
      dwIatAddr += 4;

    dwPrevApiAddr = dwApiAddr;

    // 找偷掉API操作的字节长度
    // 比如 CALL [0x00CD****]  是6个字节
    // MOV  EAX, [0x00CD****]  是5个字节
    for (int i=4; i<16; i++)
    {
      if (*(LPWORD)&apibuf[i] == 0x00CD)
        break;
    }

    //通过跳回去的地址算出跳进来的地址
    dwRCall = *(LPDWORD)&apibuf[i-2] + 4 + 5 + *(LPDWORD)&apibuf[i+3];
    
    //把 jmp CD**** 改回 CALL [IAT]. MOV EDI, [IAT] 等等
    memcpy((LPVOID)(dwRCall-0x400000+mapoffile), &apibuf[4], i-2-4);
    memcpy((LPVOID)(dwRCall-0x400000+mapoffile+i-2-4), &dwIatAddr, 4);

    r = fread(apibuf, 16, 1, fp);
  }

  fclose(fp);

  // 2.exe是最终文件
  fp = fopen("e:\\2.exe", "wb");
  fwrite(mapoffile, 0x42000, 1, fp);
  fclose(fp);

  delete[] mapoffile;
}


学习