• 标 题:MP3音频录音机v5.10脱壳
  • 译 者:softworm
  • 时 间:2004-11-30
  • 链 接:http://bbs.pediy.com

不清楚这个SDP究竟是什么版本,总之不是以前碰过的那个J。用的是修改版的OllyDbg 110,OllyScript 0.92

 

1. 测试

 

事先已经知道是用SDP做的,想看看是否为双进程版本。直接运行,LoadPE只看见一个进程。用OD加载,因为Single Step Event停在这里:

 

 

IDA中的EP5E2000,而且不象ExeCryptor,没有TLS Callback Function。修改OD设置:


 

停在ntdll中。再对5E2000下断,可以停下。清除该断点,不忽略所有异常,IsDebuggerPresent隐藏OD,F9运行。

 

直接运行,WinHex搜索,用什么版本保护的?文件头中的标记:

 

 

提示信息:

 

不会是破解版本吧,或许注册版本也有这个?

写个简单的OllyScript,记录异常次数。之所以用script而不是直接用手按,是因为SDP对运行时间的检测很严J

 

可以看到,10shift-F9后报debugger detected

 

 

2. debugger检测

 

10shift-F9,这里异常:

 

script走到5E2EFA,这个异常的handler没有改变context中的eip,SEH handler中返回异常地址继续执行。dump解出的代码,去掉Junk codeJ

 

跟第10次异常后的代码,唯一的一次判断在这里(不跳,往下执行即显示debugger detected):

 

 

修改script,在这里jmp5E2F7F。程序继续运行了。下面又是一次异常,

 

这里如果shift-F9,原来的进程结束了。新启动一个进程继续运行。

 

 

3. 进程逃逸

 

从上面这个异常(5E313D)handler开始跟。有个问题:debugger下运行有时会失败,不能启动子进程。一旦失败一次,就再也不能正常运行起来了。不知道是不是程序做了什么手脚。在我的W2K SP4WinXP Pro下都如此。

 

 

这是创建新进程的代码:

 

创建进程时的参数:

 

父进程和子进程使用同一个EXE文件,参数也没有任何特殊之处。

执行CreateProcessA后的返回地址。

 

 

创建新进程之后,父进程立即就退出了,子进程独立运行。显然,这里并不象ArmadilloNanaomites那样让人头疼J 。创建新进程的唯一目的就是摆脱debugger

 

为什么新的进程不能运行了?注意在调用CreateProcess时传递的StartInfo结构没有正确填入数据。

 

全部为0。是否程序发现正在被调试,设置了某些标记? 试试手动填入cb等数据,仍然不行。从任务管理器的显示看,似乎这个新创建的进程仍然在把自己当父进程运行, 大概是某些用于同步的内核对象出了问题。

 

既然子进程完全独立运行,可以甩开上面的问题,直接使程序以子进程方式运行,继续调试。

 

 

4. 分离子进程

 

OllyScript在上面的5E3194jmp,强制以子进程方式运行。记录异常和中断。

 

 

也是10,后面的2个记录是异常。程序直接退出了,弄错了? log,判断应该是正确的。跟一下。

 

handler 5E4590跟起。到这里,出现log中的第1个内存访问异常。

 

 

 

这个异常被OllyDbg处理了。用插件避开这个anti-debug技巧。

文本框: THEORY:

When  exception happens, Win2K/XP gives control to NTDLL!KiUserExceptionFilter,
which  in turn calls KERNEL32!UnhandledExceptionFilter. This function checks if
faulty  software  is  being  debugged.  If  not, UnhandledExceptionFilter calls
softwares' exception handler.

SOLUTION:
 
Patch  KERNEL32!UnhandledExceptionFilter  so that softwares' exception handler
is  always  called.  Used  signatures  work  for both Win2K SP4/WinXP SP1, and
hopefully for all other versions.
 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 


OllyDbg中停在系统断点时就运行UnhandledExeptionFilter插件。仍然用前面的script记录。这次程序正常运行了。

 

 

 

这次记录为0x35。注意异常地址并不在壳代码空间(因为程序在开始运行时总有一个数组越界错误,脱壳后倒好了J),后面的可能是控件抛出的。

 

这是壳代码执行的最后一个异常,计数为0x2E

 

另外,注意这里:

 

5E78E2这个地址在log中反复出现,后面往往有Module载入。这里是处理IAT的地方?

 

 

5. 寻找OEP

 

Script停在上面记录的壳代码最后一个异常处(5E707A)handler结束后回到异常处继续。

F7单步几次就到OEP了。

 

 

ret到这里。

 

 

没有stolen code?不会吧。可能找错了。先dump出来再说。用OllyDump

 

 

anti-dumpJ。直接在OllyDbg中修改每个section的内存块属性。

 

 

这次可以了。

 

用资源编辑器看看,Delphi/BCB程序。用IDA反编译一下dumped.exe

 

 

看起来OEP是对的J

 

 

6. 修复IAT

 

IAT从这里开始:

 

结束:

 

size = 4D58E4 – 4D5168 = 77C

 

单步跟了几个API调用,既有redirected到壳中的,也有由壳代码emulate的。从5E78E2处的异常入手, 在第一次断下开始跟(counter=3)

 

API(MessageBoxA)的地址保存在了2个地方:壳空间和heap。这个地址比进程的映射地址更低。在OEP可以看到,IAT中很多entry是指向这里的。

 

 

5E78E21次异常时,处理user32,GDI32, ADVAPI32, RPCRT4, IMM32,LPK6dllKERNEL32api已经在更早的时候处理过了。此时上面已经填入了约60kernel32api地址。

 

相关代码与SDP以前的版本相似:

 

需要注意的dll仍然是: kernel32, user32, advapi32, shell32,gdi32,以及sdprotector.dll

在决定以子进程运行前,壳代码处理了上述几个dll,获得的API地址保存了2,分别在壳空间和堆中。

 

现在试试跟从按子进程运行后,这段代码的处理。试跟了2,并非5E78E2异常都与IAT相关。用脚本试试:

文本框: 005E78E2   Single step event at MP3_Audi.005E78E2
             counter_child = 00000013

 

 

 

 

 


到这里IAT中已经填入了一些重定向值了。从上一个int 3异常开始跟。

 

 

这里开始了。注意这2个函数:

 

进去看看:

 

连续6个这样的函数。5EEB3D进去有些计算,CRC32(有个初始化256 byte向量的动作J)。不过这已经不重要了,只要稍微想一想,就明白这是在干什么。6个特殊对待的dll,显然这些函数用于判断J

 

 

IAT中的数据规范,基本是这样的格式。 

 

 

什么时候变成指向14xxxx5Exxxx就是被处理过了J

 

0x12int 3 -> 处理kernel32.dll

 

(这个也许不跳也行?我没有试J)

 

 

0x13  Single step event -> 处理user32.dll

 

 

0x14  Single step event -> 处理advapi32.dll

 

 

依此类推,直到IAT全部填充完毕。

 

 

全部有效。Fix dump,运行:

 

 

只脱掉壳,并未破解。