叶子青 发表于 2018-7-5 00:48

菜鸡尝试手动脱壳

之前没有真正动手脱过壳,这边看了一些教程总是半懂不懂,看是有手上有个简单的例子,就拿来做练习的对象了,过程有点繁琐
首先进行查壳,可以发现他是RLPack壳

打开OD查看入口处,入口处存在一个pushad所以这种情况下直接使用直接ESP定律,在ESP上下断点执行会在popad时断下

此处被断下继续f8向下跟踪

紧接着又有一个Pushad,继续esp定律更随


断在了这个地方这里应该就是OEP的附近了

此时eax的值为0x446a52
可以看到上图中这里的代码所做的处理,将eax,ebx,ecx....这些通用寄存器存入了0x446a52+0x535e往后的地址中
这个地方我F8跟踪进,将各个寄存器的值写入了内存然后将ebp+0x535a也就是0x446a52+0x535a=44bda8的内容写入edi
并且将ebp+0x5356=0x446a52+0x5356=44bdac的内容存入esi
此时寄存器列表中ESI=00D70000,EDI=00D50000
在数据窗口更随这两个值

可以看到00D70000中存在一大堆的数据,00D50000里面什么也没有,我就没截图贴上来

继续在刚才EIP的基础上单步F8继续往下跟踪走到JMP跳过去
他先拿ESI所指向的地址也就是D70000里的数据和0作比较非0就跳到如下图的这个位置



可以看到这个下面他一直在拿esi所指向的内容和0,1,2.。。。做比较,我们当前esi指向的地址是D70000里面的内容为0x2,我们继续F8向下跟踪


当到达与0x2做比较的位置,不再跳转,当前保存了一下环境并清零ecx,然后将当前指针esi+4的内容压栈(也就是我们当前D70000向下的四字节的内容)
我们继续跟踪这个函数进到下面这个CALL里面
此时进入这个函数,清点下目前寄存器的值
ebp=eax=446a52(也就是我们之前保存那一堆寄存器的内存块0x446a52+0x535a的基址)
而此时ESI指向的是我们之前读到的数据块首地址(D70000),edi指向的是为0的数据块的首地址(D50000)

在449352这行
这几句话将之前push到堆栈的内容esi+4的内容复制给了edi指向的地址也就是D50000
然后向堆栈中压入两个值(-4和8),跟踪这个函数

在这个位置我们清点下手上寄存器的值
ecx为我们之前存储的基址0x446a52,EDX和EBX至今没怎么变过
继续向下跟踪


在448be7这个位置,将之前压栈的两个参数也就是 8给了eax -4给了ebx
然后接下来进行比较判断eax的值是多少继续往下跟踪

判断出eax=8后将ebx(-4)加给了ebp+0x537a
而此时EBP的值是我们之前存储一大堆寄存器的基址0x446a52,ebp+0x537a对应的就是之前存储的ESP

上图是之前存寄存器时的图,也就相当于对ESP存储的那块内存-4(模拟提升堆栈?)
紧接着在下一行也就是448f26这一行将edi的值(d50000)+4

可以猜测,他应该是用基址0x446a52+0x535e为起始地址后面的这些内存块动用做模拟我们计算机的8个通用寄存器使用,
然后将edi所指向的D50000作为了模拟的堆栈,而刚才那顿操作就相当于往虚拟的堆栈里压入了一个值并提升堆栈
那么相应的ESI所指向的D70000应该就是类似于我们的EIP指向代码的存在
那么假设这个是类似于压栈的操作那前面应该有对堆栈赋值的操作,所以我回头查找,在449352行,就是将esi+4位置的数据
存入我们的虚拟堆栈D50000的动作
那么当前的操作就像是我们硬编码执行的过程,首先识别最前面的操作指令,判断指令类型和指令长度,然后后面跟着的是
我们的指令操作数,
我们继续f8向下跟踪

发现在这个位置我们的esi加0xc然后向上跳转来到了刚才那个判断类型的位置



基本上可以确定这里模拟了我们计算机的工作原理,
内存D70000这里存放着我们即将执行的代码 ESI就像EIP一样在这个上面读取指令
内存D50000这里作为我们模拟的堆栈空间
然后将0x00446a52为基址如下图中的这些内存块当做我们的寄存器组
然后循环遍历D70000中的代码,
例如首先看到我们的第一个虚拟的指令操作数为0x2,将操作数0x2后4字节的数据作为操作数压入虚拟的堆栈
其中就包括将这个数据写入虚拟堆栈,并提升栈空间
然后虚拟的EIP加0xc(也许是因为在他设计的这个体系中他这个指令占三个DWORD)指向下一条指令继续循环
所以当前第一条指令就是PUSH 0

那好我们继续往下跟踪验证下我们的猜想
此时ESI指向了我们D70000+0C也就是之前假设的第而条指令的位置



我们就像之前一样F8往下跟踪,此时指令为0xc


在这里面先做了一堆复制(一时没看懂在干嘛先放过去)
此时ebx所指向的事4485c7这个地址,在当前EIP网上的两条指令,取了一个地址然后与当前虚拟操作指令的
第一个操作数做差然后存在了EBX+0X81的位置
然后从我们虚拟的寄存器ESP的值复制给真正的esp
再讲虚拟堆栈栈底的值取出复制给esi(相当于虚拟的EBP)
此时edi为当前虚拟堆栈栈顶的值(应该相当于虚拟的ESP)
然后继续跟踪,他在4480d6比较esi与edi的大小
esi小于edi,就将esi所指向的虚拟堆栈中的数据压入真实的堆栈,然后esi+4再与edi做比较直到esi==edi(这个操作等于将虚拟堆栈中的值都拿到我们真实的堆栈中)


然后在此处将虚拟寄存器中的值全部赋值给真实的寄存器(这里我猜测即将执行的代码需要与我们实际的代码对接,比如调用我们实际的函数或者API或者跳转一类的操作)
然后在448647这一行果然调用了一个进入其他位置的函数
在这里有一个细节注意,注意当前这个CALL的地址是448647
在我们之前刚刚判断当前指令为0c的时候我们做了一大堆复制
其中在复制后面还做了一堆加减的操作,当时我看到这个操作的时候第一反应就是这个和我们硬编码
计算段跳转和短调用后面的操作数的操作非常像,计算偏移值
我们回去继续分析那段代码还是看之前执行到这个位置的图如下图

当时的ebx的值为0x4485c7
而第4485f4这一行就是将eax的值赋值给ebx+0x81也就是448648,这个地址刚好就是我们刚才
看的那个CALL要跳转的地址的操作数,可见在这个位置他对自己的这个函数做了一个简单的
HOOK(我也不知道这样算不算HOOK)而eax的来源我们来看一下,来自esi+4,而esi+4就是我们
当前指令后面的操作数,后面的减法操作就是类似于硬编码中短跳转指令计算偏移的操作,
以下是D70000的内存窗口

那么第二条指令实际上相当于CALL 或者 JMP 00419AE6 因为之前分析的时候他在跳转之前压栈了返回地址所以当前指令是CALL
CALL 00419ae6


同样在CALL完之后再将真实的寄存器值再写回我们的虚拟寄存器
后面一堆恢复的操作以后又将虚拟EIP指向下一个指令的位置(+0xc)可以看到在他这个体系中所有指令和操作数都是0xc字节的
后面我就不一条一条看了,因为目前我手上没有这个加壳软件的工具,不然可以直接调试加壳软件,找到他做转换的那个地方
然后直接把他的代码抠出来就不需要这样一点一点的分析了(心累)然后直接编写脚本把这块代码修复
不过好在这里的这些虚拟代码只有四种:

00 00 00 02 xx xx xx xx 00 00 00 00   Push xxxxxxxx
00 00 00 03 00 00 00 01 00 00 00 00   PUSH EAX
00 00 00 0c xx xx xx xx 00 00 00 00   CALL xxxxxxxx
00 00 00 0b xx xx xx xx 00 00 00 01   MOV DWORD,eax


那么这段代码还原出来就是

PUSH 0
CALL 00419AE6
MOVDWORD ,EAX
CALL 004013D3
PUSH 0
PUSH 00401D07
PUSH 0
PUSH 0041D021
PUSH DWORD
CALL 419A32
PUSH 0041D018
CALL 00419AB6
PUSH EAX
CALL 00419ABC
然后我们把这部分恢复后的OEP写回去就完事了


我这里通过脚本写入

var        padder

mov        padder,00401000
mov        ecx,00000040

mov        ebx,padder
mov        ,#6A00E8DF8A0100A3AEF34100E8C20300006A0068071D40006A006821D04100FF35AEF34100E888A01006818D04100E8828A010050E8828A01009060E8938A01#
修复后的效果如下,此处才是真正的OEP


接下来我们基本上就可以直接脱壳了,但是这里还是检查下IAT表是否需要修复
我在这里跟入了第一个函数,这个函数在这里经过了一个跳转表,我第一次跟入的时候翻的比较快,最终进到了KERLAN32.DLL的领空也就是说这里调用的API

可见这个地方应该是一个FF25间接CALL的跳转表(那个nop应该就是加壳软件修改这里时整出来的多余字节)
F8往下跟踪 可以发现这里下面的这些代码的结构都非常类似,最终都通过了一个的位置走掉

继续跟踪

到了这个位置,暂时看不出什么继续往下跟踪直到有跳转


然后就到了这儿,这个地方算是出现了一个间接跳转的JMP,我们查看下0xD804E6里面都有啥

于是到了这步,这个地方已经是KERL32.DLL的领空,可以看到这个里面最终调用了GetMoudleHandleW
这块应该是GetMoudleHandleA不过不是正正当当的入口位置,不过观察我们当前EIP前面没执行的代码,
可以发现在我们跳进来之前已经执行了类似的代码
那可以确定这块就是IAT了并且他修改了IAT,还把调用的API偷出来几个字节,这样我们调试的时候
直接在API最开始的地方下断点可能就会发现断不下来

那我们现在要做的就是,在最开始jmp列表的那个位置
然后将JMP的地址指向我们修正后的真正的API函数的位置

脚本的大致思路就是定位函数被调用的一路上所有的跳转指令,然后获取他们跳转的目标
用脚本一路跟踪到达进入相应API的前一层函数,然后计算被偷取的代码的数量,然后修正API的地址到最前面的JMP表
脚本代码:


var        temp        //临时变量
var        iat        //需要修改的跳转地址
var        adder        //临时地址
var        adder1        //临时地址
var        sesp       
var        seip

//保存现场
mov        sesp,esp
mov        seip,eip
mov        iat,00401000

loop:
mov        esp,sesp
//定位JMP列表
find        iat,#e9????????90#
cmp        $RESULT,0
je        exit
mov        iat,$RESULT
gci        iat,DESTINATION
mov        adder,$RESULT
//定位间接跳转
find        adder,#ff25????????#
mov        adder,$RESULT
gci        adder,DESTINATION
mov        adder,$RESULT

//定位第三个跳转
find        adder,#61e9????????60#
mov        adder,$RESULT
//此处下硬件执行断点
inc        adder
bphws        adder,"x"
mov        eip,iat
esto
gci        adder,DESTINATION
mov        adder,$RESULT

//计算被偷指令字节数
find        adder,#ff25????????#
mov        adder1,$RESULT
mov        temp,adder1
sub        temp,adder
//定位真实函数地址
gci        adder1,DESTINATION
mov        adder,$RESULT
sub        adder,temp
//修复JMP表指令
eval        "jmp {adder}"
asm        iat,$RESULT
add        iat,5
jmp loop


exit:
mov        esp,sesp
mov        eip,seip
脚本修复效果如下


然后再通过通用输入表修复工具把这里的E9直接跳转修改为FF25间接跳转完成IAT表的修复


接下来就直接DUMP然后修复IAT就OK了

叶子青 发表于 2018-7-5 12:28

byh3025 发表于 2018-7-5 12:21
这是什么壳?脚本通用吗?

RlPack,修复IAT那个脚本针对ASM这类语言的应该是通用的吧,我这里写的这个脚本主要是针对你把FF25改为E9的这种IAT加密,其他的应该不行,前面那个修复代码的我是手动把他的那个代码翻译出来的,脚本只是负责写回去,只适用我当前这个软件

叶子青 发表于 2018-7-9 18:40

Hmily 发表于 2018-7-9 16:02
是原创吗?没经验直接就搞rlpack全保护啊?没vm的年代它也是中等加密壳了。

恩原创,之前看过一个脱这个壳的视频,但是我看他什么都没分析直接用的特征码,我就自己找了个这个壳的软件用自己学过的东西分析处理了

放火案 发表于 2018-7-5 10:39

楼主你厉害,我看的头晕的很

soyo136 发表于 2018-7-5 10:43

学习一下,感谢楼主分享自己的经验

BIJIE 发表于 2018-7-5 11:11

学习了!楼主很厉害啊!

弑神、残血 发表于 2018-7-5 11:26

厉害了,加油

wo452323123 发表于 2018-7-5 11:55

厉害了我的楼主。根本看不懂

叶子青 发表于 2018-7-5 12:09

你们是在吐槽我写的太乱了么{:1_911:},这个是我这边脱壳的时候一边跟踪一边记录的,确实有点乱2333333:lol

叶子青 发表于 2018-7-5 12:10

wo452323123 发表于 2018-7-5 11:55
厉害了我的楼主。根本看不懂

你们是在吐槽我写的太乱了么{:1_911:},这个是我这边脱壳的时候一边跟踪一边记录的,确实有点乱2333333:lol下次注意

gunxsword 发表于 2018-7-5 12:16

看的好晕.楼主真的是第一次?

byh3025 发表于 2018-7-5 12:21

这是什么壳?脚本通用吗?
页: [1] 2 3 4 5 6 7
查看完整版本: 菜鸡尝试手动脱壳