逆解压缩算法之前 一直以为需要知道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逆出来的算法

上传的附件 upx.rar

  • 标 题:答复
  • 作 者:Loka
  • 时 间:2009-04-03 19:17

应该不用这么麻烦,用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;
}