首页
社区
课程
招聘
[原创]UPX解压缩算法逆向
发表于: 2009-4-3 17:40 19554

[原创]UPX解压缩算法逆向

2009-4-3 17:40
19554

逆解压缩算法之前 一直以为需要知道N多数学上的东西  逆了后才知道 只要知道基本的逻辑就可以了

初次逆解压缩算法的同学 感到最困难的应该是  跟标志位有关的 加减法 以及条件跳转

这些东西很难跟高级语言联系在一起 用高级语言表示特别麻烦 我在这个地方 也是绕了很大的一个圈子

注:因为水平比较菜 所以我所说的逆向只是 功能相同 逻辑相似  而非指令一模一样

面临失业  没有心情继续分析壳了  很久以前就想逆解压缩算法了  现在也有时间了

仔细看下 UPX的解压缩算法   里面最重要的就是两块指令

1:

0040ED1E    01DB            ADD EBX,EBX                                  ;EBX * 2
0040ED20    75 07           JNZ SHORT x.0040ED29                     ;检测EBX 是否为0
0040ED22    8B1E            MOV EBX,DWORD PTR DS:[ESI]           ;
0040ED24    83EE FC        SUB ESI,-4                                      ;ESI + 4
0040ED27    11DB            ADC EBX,EBX

0040ED29  ^ 72 ED          JB SHORT x.0040ED18

这块指令的 最阴的地方就是SUB ESI, –4       SUB 指令影响CF标志  下面紧跟着就是一个 跟标志位有关加法

C语言中要想知道SUB执行后 CF标志为多少 必须要把ESI的值 送到一个大于4字节的 数据中  这里我用了unsigned

__int64 8字节的数据来表示,而这块指令 我以getbit函数来表示(也可以用宏 或者inline 但是我偏向于函数)

int getbit(unsigned __int64 *pcom_dword, unsigned char **ppsrc)
{
    unsigned __int64 temp;
   
    *pcom_dword &= 0xffffffff;
    (*pcom_dword) *= 2;
    if(!(*pcom_dword & 0xffffffff))
    {
        *pcom_dword = *(unsigned int *)(*ppsrc);
        temp = (unsigned int)(*ppsrc);
        temp -= (unsigned int)(-4);//temp就是为了知道 SUB后的CF标志 定义的变量
        (*ppsrc) += 4;
        *pcom_dword = ((temp >> 32) & 1) + *pcom_dword + *pcom_dword;
    }
    return (int)((*pcom_dword >> 32) & 1);
}

几句汇编指令  变成 这么大一坨 惭愧
=================================================
根据4L高手的提示 修改了 下
int getbit(unsigned int *pcom_dword, unsigned int **ppsrc)
{
        int temp;

        temp = ((*pcom_dword)>>31)&1;//得到 符号位
        (*pcom_dword) <<= 1;
        if(0 == (*pcom_dword))
        {
                *pcom_dword = **ppsrc;
                temp = ((*pcom_dword) >> 31) & 1;
                (*pcom_dword) <<= 1;
                *pcom_dword += ((unsigned int)*ppsrc >= 0xFFFFFFFC ? 0 : 1);
                (*ppsrc)++;
        }
        return temp;
}

最初 想得到标志位 也是通过32位表示的  方法是后0~30位相加  再把 2个操作数 与 相加后的和  的第31位相加 就
知道CF了    后来觉得 这样相加 实际上就是模拟64位相加  索性用64位表示算了
这里修改成32位 简洁了很多   是因为 加法的2个操作数是一样的  向左移位就可以了

getbit函数改成这样 就可以直接替换原来的getbit解压了  果然我的思路过于狭窄
再次膜拜下 4L的高手
=========================================================
2:

0040ED30    01DB            ADD EBX,EBX
0040ED32    75 07           JNZ SHORT x.0040ED3B
0040ED34    8B1E            MOV EBX,DWORD PTR DS:[ESI]
0040ED36    83EE FC        SUB ESI,-4
0040ED39    11DB            ADC EBX,EBX
0040ED3B    11C0            ADC EAX,EAX
0040ED3D    01DB            ADD EBX,EBX
0040ED3F  ^ 73 EF          JNB SHORT x.0040ED30
0040ED41    75 09           JNZ SHORT x.0040ED4C
0040ED43    8B1E            MOV EBX,DWORD PTR DS:[ESI]
0040ED45    83EE FC        SUB ESI,-4
0040ED48    11DB            ADC EBX,EBX
0040ED4A  ^ 73 E4          JNB SHORT x.0040ED30

这块指令 没有用函数表示  只是同样是一坨   再次惭愧

//EBX 对应com_dword  ESI 对应psrc  EAX对应off

do
{
    do
    {
        off = off * 2 + getbit(&com_dword, &psrc);
    }while(com_dword =com_dword + com_dword, ((com_dword >> 32) & 1) == 0);
    if(com_dword & 0xffffffff)
    {
        break;
    }
    com_dword = *(unsigned int *)psrc;
    temp = (unsigned int)psrc;
    psrc += 4;
    temp -= (unsigned int)(-4);            
}while(com_dword = com_dword + com_dword + ((temp >> 32) & 1), ((com_dword >> 32) & 1) == 0);

这两块指令弄出来后 只剩下基本的逻辑了 没什么难度了
逆这个东西 的作用就是知道怎么用C语言来表示标志位了 再来 就是 现在瞄下 压缩算法 就知道 从哪里跳出来了 不用靠猜的了  

UPX的压缩级别不同 解压缩算法也是不同的  别指望 逆出来的能解压缩所有UPX加过壳的代码

解压缩算法一直是心里的一根刺  本来想好好写写 逆向过程中的收获  逆完后 发现 什么都写不出来只能寥寥几句

附件里x.exe就是UPX加过壳的EXE, upx_re.c里存放的就是 根据x.exe逆出来的算法


[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

上传的附件:
收藏
免费 7
支持
分享
最新回复 (27)
雪    币: 47147
活跃值: (20445)
能力值: (RANK:350 )
在线值:
发帖
回帖
粉丝
2
估计会有人联系你了,前段时间还碰到有公司在招人
2009-4-3 17:46
0
雪    币: 179
活跃值: (15)
能力值: ( LV12,RANK:330 )
在线值:
发帖
回帖
粉丝
3
外面形势似乎 不太好
公司里有个强人  2个星期前就投简历了  现在 还没面试消息

一个朋友说 3月份 是外企裁员高峰期  结果我就赶上了
生活还得继续  希望这段时间别过得太灰暗。。。
2009-4-3 17:56
0
雪    币: 993
活跃值: (442)
能力值: ( LV12,RANK:403 )
在线值:
发帖
回帖
粉丝
4
应该不用这么麻烦,用32位足够了。
int getbit(unsigned int *pcom_dword, unsigned int *ppsrc)
{
    int temp;
    temp = ((*pcom_dword)>>31)&1;
    (*pcom_dword) <<= 1;
    if(0 != (*pcom_dword))
    {
        *pcom_dword = *ppsrc;
        temp = ((*pcom_dword)>>31)&1;
        (*pcom_dword) <<= 1;
        *pcom_dword += ((unsigned int)ppsrc>=0xFFFFFFFC ? 0 : 1);
        (unsigned int)ppsrc += 4;
    }
    return temp;
}
2009-4-3 19:17
0
雪    币: 846
活跃值: (221)
能力值: (RANK:570 )
在线值:
发帖
回帖
粉丝
5
楼主被裁了,让我想起某公司。。。。不过不是外企。。。
2009-4-3 19:30
0
雪    币: 179
活跃值: (15)
能力值: ( LV12,RANK:330 )
在线值:
发帖
回帖
粉丝
6
先遥拜下高手

我用 你的getbit函数  解不开  死循环一直
= =人品?
2009-4-3 19:31
0
雪    币: 370
活跃值: (15)
能力值: ( LV9,RANK:170 )
在线值:
发帖
回帖
粉丝
7
不知道发起一个是否被裁+被裁几次的投票  会被踩
2009-4-3 19:42
0
雪    币: 993
活跃值: (442)
能力值: ( LV12,RANK:403 )
在线值:
发帖
回帖
粉丝
8
int getbit(unsigned int *pcom_dword, unsigned int *ppsrc)
我把第二个参数略做了点改动
2009-4-3 19:49
0
雪    币: 179
活跃值: (15)
能力值: ( LV12,RANK:330 )
在线值:
发帖
回帖
粉丝
9
晕 没注意到这个 。。。。
thx

先吃饭  过会 出去 吃烧烤   散心
2009-4-3 20:01
0
雪    币: 101
活跃值: (12)
能力值: ( LV12,RANK:210 )
在线值:
发帖
回帖
粉丝
10
病毒公司都裁员么
2009-4-3 20:54
0
雪    币: 99
活跃值: (2433)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
11
UCL是开源的,为啥还要逆呢?
2009-4-3 21:23
0
雪    币: 179
活跃值: (15)
能力值: ( LV12,RANK:330 )
在线值:
发帖
回帖
粉丝
12
是有源码  不过  在好几个文件中找  解压缩代码  是个折磨= =

以前 逆另一个壳的时候   只剩压缩算法  没逆出来   后来只是嵌汇编 把压缩算法 嵌进去  做了个静态 脱壳机    心有不甘   现在有时间了  就把压缩算法逆了一遍   以偿宿愿

另外 其实一直想做 仿真机  可惜以前  对那些标志位 什么的  都不会弄   逆了这个 心里有点底了  积累啊积累
2009-4-3 21:52
0
雪    币: 99
活跃值: (2433)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
13
你看的是asm?c的文件很少啊,n2b_d.c,n2d_d.c,n2e_d.c和getbit.h就行了。三个c文件是因为本来就有3种压缩算法。
2009-4-4 09:29
0
雪    币: 179
活跃值: (15)
能力值: ( LV12,RANK:330 )
在线值:
发帖
回帖
粉丝
14
怎么我这的源码  都是C文件               
刚刚仔细找了下  解压缩源码 都在compress*.cpp里面
版本不同应该
case M_NRV2B_8:
        r = ucl_nrv2b_decompress_safe_8(src,src_len,dst,dst_len,NULL);
        break;
    case M_NRV2B_LE16:
        r = ucl_nrv2b_decompress_safe_le16(src,src_len,dst,dst_len,NULL);
        break;
    case M_NRV2B_LE32:
        r = ucl_nrv2b_decompress_safe_le32(src,src_len,dst,dst_len,NULL);
        break;
    case M_NRV2D_8:
        r = ucl_nrv2d_decompress_safe_8(src,src_len,dst,dst_len,NULL);
        break;
    case M_NRV2D_LE16:
        r = ucl_nrv2d_decompress_safe_le16(src,src_len,dst,dst_len,NULL);
2009-4-4 10:06
0
雪    币: 110
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
15
祝你好运
楼主不要灰心
2009-4-4 10:48
0
雪    币: 99
活跃值: (2433)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
16
你要看UCL的源码,UPX源码中不包含压缩和解压缩代码。
2009-4-4 15:09
0
雪    币: 179
活跃值: (15)
能力值: ( LV12,RANK:330 )
在线值:
发帖
回帖
粉丝
17
多谢提点
2009-4-5 11:28
0
雪    币: 192
活跃值: (70)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
18
这么巧 我也正在研究它  惭愧
2009-4-5 16:58
0
雪    币: 2604
活跃值: (64)
能力值: (RANK:510 )
在线值:
发帖
回帖
粉丝
19
支持楼主。
别灰心。机会一定会有的!说不定,下个单位还更好呢!
2009-4-6 23:37
0
雪    币: 362
活跃值: (25)
能力值: ( LV7,RANK:100 )
在线值:
发帖
回帖
粉丝
20
祝君好运
2009-4-7 09:12
0
雪    币: 11121
活跃值: (158)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
21
这么牛的人,竟然被裁,我们这小菜,怎么过啊。
趁现在在学校还有时间,还多多努力啊
2009-4-7 10:17
0
雪    币: 179
活跃值: (15)
能力值: ( LV12,RANK:330 )
在线值:
发帖
回帖
粉丝
22
已在主贴修改
2009-4-7 16:52
0
雪    币: 200
活跃值: (16)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
23
高手都被裁,我等小菜怎么过啊
2009-4-8 18:01
0
雪    币: 224
活跃值: (147)
能力值: ( LV9,RANK:970 )
在线值:
发帖
回帖
粉丝
24
LZ可以试试这里的
http://bbs.pediy.com/showthread.php?t=85011
2009-4-12 18:58
0
雪    币: 190
活跃值: (10)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
25
IDA F5
2009-4-13 00:25
0
游客
登录 | 注册 方可回帖
返回
//