首页
社区
课程
招聘
[原创]第2阶段第3题提交
发表于: 2007-9-6 00:35 7340

[原创]第2阶段第3题提交

2007-9-6 00:35
7340
简单说明:
0,和1~9分别是不同的压缩方法, 为zlib的inflate和aplib的变形
很简单的压缩壳, 大概解码后, 构造一个异常, 跑到smc的地方, 然后进行e8e9修复,
padding0等操作, 在构造一个异常, 来计算入口, 修复导入表

入口的计算比较麻烦, 需要用代码自己生成一个xor key,  还有一些api会被hook, 这张
"是/否"hook表这跟当时的地址&7的值有关, 然后根据这个表以及刚的xor key来计算入口.
其他没什么难度了, 最后一个节删了, 本来想做其他优化的, 但效果也不是很大.
因为他原来就把几个节给合并了, 需要手动到中间去找很多0的地方, 太烦琐, 而且对整个
大小的影响并不是很大. 所以就没做那么细的优化
参见附件有原代码vc7编译. 还有编好的release版.

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

上传的附件:
收藏
免费 0
支持
分享
最新回复 (3)
雪    币: 101
活跃值: (12)
能力值: ( LV12,RANK:210 )
在线值:
发帖
回帖
粉丝
2
啥都不说了。
by序号的时候hook table有点小问题。。。
上传的附件:
2007-9-6 11:34
0
雪    币: 101
活跃值: (12)
能力值: ( LV12,RANK:210 )
在线值:
发帖
回帖
粉丝
3
不知道怎么写文档。 从没写过。。
挺简单的一个壳。
1:
首先, 在最后petite追加的sfx节中, 把自己的后续处理代码, 以及原来的压缩
的节都解出来, 这里他一共用了2个算法。
0压缩 是zlib库的inflate, 应该是113版的, 因为压缩代码中可以看到这个版本号,
     根据代码的对比也知道是113版的, 网上流行的是123的最新版, 所以用123的
     www.zlib.net,  其实他是有点修改, 关键在于inflateblock函数中,
     他没有case 1的fix table, 而是case 1是原来2的dynamic table,
     所以改了一下, 另, 他是一个raw stream, 所以需要在inflateInit2调用的bitwidth中
     填写-15。
1~9压缩是aplib的一种变形, 为什么这么说呢, 因为几个关键子, d00, 500, 80太熟了。
     但是他有另几种比较值, 而且比aplib要简单, 但有雏形, 包括getbit以及getrepeat等
     还有, 他每次src->dest的时候, 都需要xor一下当时的留下size.
       算法都比较简单, 就不多说.
所以: 注定有2个stub,   所以: 需要定义2中偏移量.

2:
所有的节都解出来了后, 就构造一个异常, 跑到程序开始设置的seh去执行,
也就是第一次解出来的SMC代码.  这里, 需要修复下e8e9,  还有一个操作, 就是padding zero.
其实: 这里能知道原来的节的信息, 包括为了section align所需要的0都有,
但是我这并没优化, 因为一般样本, 这样效率不高. 除非评委改了.. 说远了.
e8e9的修复是壳经常用的手段, 因为跳的地方相对与自己的地方这个查值一般比较小.
有助于后面的压缩.  其实还包括f0这样的长跳.  代码很段. 自己看原代码吧.
再次构造一个jmp eax(eax=0)的seh, 去执行3. 同时把sfx给清楚.
把自己拷贝一点自己给原来的入口, 以给以后做变换.

3:
这里给代码进行自效验. 包括pe头的, 包括smc的. 同时需要
得到xorkey, 这个就是把smc的代码的某些字节进行一下hash,
那个fs:12, fs:2c(没记错的话), 其实就是一个0和一个1起作用. 估计是反虚拟机的..
然后不停的xor那个buf然后循环移位, 每次移动前都把自己最低位置上
这个算出来的xorkey, 跟原来的entrypoint的旁边的16个字节xor后, 这样
如果没出问题, entrypoint就是一个e9.... jmp xxxxxxxx(记错maigc x)
恢复导入表, 始终没看到重定位的信息.. 不知道他怎么敢加dll....
导入表的位置,函数名字位置跟原来没变, 只是把原来的5*4一条的导入表信息用一个4字的
firstthunk代替了.直接的dllname被拷贝到pe头去了.  因为5*4比4大嘛,  所以他敢这么放.
我这简单的把他放回去..  0000 0000 0000 pe头的名 原来的thunk.
然后2次循环, 一次是dll的, 一次是函数的, 把函数的thunk填对就ok了。
值得注意的是name和序号是不一样的, 如果是序好, 那么不走流程x.
名字就要走流程x
流程x: 每次走的时候, 每次计数值都减1, 看是否比0大, 如果没有, 那么就hook掉这个api,
并且把hook后的地址的地方&7做下一次计数值, 计数值的初史值需要从exe中读,
可能是0,1等...
最后, 把入口magic x跟api数量进行变换.
如果hook了, 就 x = ror(x-2,3) 否则就x = ror(x-1,3)
这样能算出入口来,
修正pe头, entrypoint,  imagesize, 取掉最后一个节,  然后dump就完了.

看下原代码就什么都清楚了.

这里没有idb, 所以很多东西都是凭记忆写的, 难免有失误, 见谅.
2007-9-6 21:45
0
雪    币: 846
活跃值: (221)
能力值: (RANK:570 )
在线值:
发帖
回帖
粉丝
4
第8个崩溃了
其他都可以脱,但是只有第一个脱了之后能运行

样本序号 执行结果 原始大小 解压大小
1              pass   20,480    20,480
2            fail
3            fail
4            fail
5            fail
6            fail
7            fail
8            fail  

name        起始时间        结束时间        做题时间        脱壳成功文件数        解压比例        提交次数       
jjnet        2007-9-2 12:00        2007-9-6 11:34        5734        1        1        2       

得分13.74481446
2007-9-10 15:21
0
游客
登录 | 注册 方可回帖
返回
//