IDA Pro 实战逆向破解入门到大师04:XOR加密·指针伪装·内存加密

file-20260718162640687

同学们,这又是一个极佳的新手实战案例,如果说前几个 CrackMe 还是在“玩转字符串”,那么到了 Stage 1-04,我们终于正式踏入了逆向工程的深水区:密码学与算法混淆(内存加密)

先补一句,所有的案例资源下载都在 www.52xuejishu.com,0基础学逆向,就找小迪老师

这个案例对于新手的最大痛点在于:IDA 还原出来的指针操作非常反人类。 但是别怕,有小迪老师在,让我带大家破除对指针的恐惧。

阶段一:常规清理与“反常点”嗅探

“同学们,拿到代码,轻车熟路的第一步:把熟悉的外围函数全部重命名!sub_401C85printfsub_4011EFscanfsub_403CD8system。干完这些脏活累活后,我们来看主逻辑。”

清理后的主函数如下:

  strcpy(Str2, "109!4");
  printf("Enter password: ");
  sub_402004(Str2);           // <--- 这里的操作非常可疑!
  scanf("%s", Str1);
  if ( !strcmp(Str1, Str2) )
    printf("OK\n");

file-20260718175956262


思考:

程序先是把 "109!4" 复制给了 Str2。按照之前几关的逻辑,密码应该就是 "109!4"。但是!在让用户输入密码之前,程序悄悄调用了一个 sub_402004(Str2)

这说明什么?这说明程序在内存里对刚才那个假密码进行了“加工(加密)”! 我们输入的密码最后是和加工后的 Str2 进行比较的。

阶段二:深入敌营(破解恶心的指针运算)

跟进 sub_402004,发现它只是个跳板(thunk),直接来到核心函数 sub_4088B0

file-20260718180041076

file-20260718180051104

“现在,我们要面对新手最害怕的东西了——IDA 翻译出来的奇葩指针运算 *(_BYTE *)(i + a1)。别怕,小迪老师带你们一行一行把它‘说成人话’!”

展示核心代码并进行拆解:

int __cdecl sub_4088B0(int a1) // a1 其实就是传进来的字符串 Str2 的地址
{
  int result; 
  int i; 

  for ( i = 0; *(_BYTE *)(i + a1); ++i )
  {
    *(_BYTE *)(i + a1) ^= 0x55u;
    result = i + 1;
  }
  return result;
}

硬核知识点拆解(重点讲解):

  1. i + a1 是什么? a1 是字符串的首地址(比如地址是 1000)。当 i=0 时,它是第一个字符的地址;i=1 时,它是第二个字符的地址。
  2. (_BYTE *) 是什么? 由于 IDA 暂时不知道 a1 是个字符串(所以给它标了 int 类型),为了读出一个字符,它必须强行把这个地址转换成字节指针(单字节)
  3. 最外层的 * 是什么? 指针解引用!拿到那个地址里存的具体字符。
  4. 一句话总结: *(_BYTE *)(i + a1) 这种吓人的写法,其实就是 C 语言里最简单的数组访问:a1[i]

阶段三:算法揭秘与密码还原

把代码翻译成“人话”后,这个加密算法其实简单得令人发指:

for ( i = 0; a1[i] != '\0'; ++i ) // 当 a1[i] 不是字符串结尾时循环
{
    a1[i] = a1[i] ^ 0x55;         // 将每个字符与 0x55 进行异或运算
}

“真相大白了!这是一个非常经典的单字节 XOR(异或)加密。在逆向工程中,异或操作有一个极其美妙的特性:它是对称的! 也就是说,如果 A ^ 0x55 = B,那么 B ^ 0x55 必定等于 A。这经常被用来做简单的隐藏。”

** 小迪老师和大家一起算真密码:**

原始假密码是:"109!4"

我们需要将它的每一个字符对应的 ASCII 码,与 0x55 进行异或(你可以打开 Windows 程序员计算器,或者写个极其简单的 Python 脚本):

  • '1' (十六进制 0x31) ^ 0x55 = 0x64 -> ASCII 字符 d
  • '0' (十六进制 0x30) ^ 0x55 = 0x65 -> ASCII 字符 e
  • '9' (十六进制 0x39) ^ 0x55 = 0x6C -> ASCII 字符 l
  • '!' (十六进制 0x21) ^ 0x55 = 0x74 -> ASCII 字符 t
  • '4' (十六进制 0x34) ^ 0x55 = 0x61 -> ASCII 字符 a

所以,经过加密函数加工后,内存里的 Str2 变成了 "delta"

真正的通关密码就是:delta

阶段四:给 IDA 施加魔法(工具调校展示)

最后,作为大师级的收尾,小迪老师一定要教大家怎么让 IDA 自己把那些难看的代码变漂亮。

  1. 回到 sub_4088B0 的定义处。
  2. 选中参数 int a1,按下快捷键 Y (修改类型)。
  3. 将类型强行改为 char *a1
  4. 按下 F5 刷新。

    file-20260718180328624

见证奇迹的时刻: 刚才那堆恶心的 *(_BYTE *)(i + a1),会瞬间变成干净清爽的 a1[i]

给新手的 Takeaway (课后总结):

  1. 不要相信眼睛看到的硬编码字符串:只要字符串在比对之前被函数碰过,它就一定被加工过了。
  2. 看穿 IDA 的指针伪装:记住 *(_BYTE *)(变量 + 索引) 这个句式,以后看到它,在大脑里自动替换成 数组[索引]
  3. 掌握异或 (XOR) 特性:遇到 ^ 符号,要知道这是最低成本的加密/解密方式。
请登录后发表评论

    没有回复内容