VB 调试之 P-Code 替换操作码

使用工具

  • OllyDbg 1.10原版,简称OD
  • OD 汉化插件均来自互联网;
  • CrackMe 和 opcodes.txt来自互联网,仅供学习使用;
  • 文中特殊数字均是HEX,为了书写方便采用DEC

分析思路

  1. 运行程序,程序会先弹出一个 NAG 窗口,点击确定后弹出主窗体:

    运行程序

  2. 导入OD开始分析,首先按照常规思路,既然有弹窗,肯定会使用 API:rtcMsgBox

    查找API

    查看 API 列表,找到rtcMsgBox设置断点,然后运行程序;

  3. 程序中断后,在栈窗口反汇编窗口跟随到返回位置:

    反汇编窗口跟随

    在调用位置设置断点,然后重载并运行程序;

    在调用位置设置断点

  4. 调用指令是CALL EAX,当前 EAX 值为 401000,Ctrl + G 跳转到 401000,正是rtcMsgBox

    401000

    按下-减号键,回到断点位置,既然是调用函数,CALL 上面的指令就是它的参数,这种传参方式在 P-Code 中很常见,还没有完,继续;

    CALL的参数

    CALL 的参数到底是什么呢?

    根据上面的代码逻辑,获取一个操作码后无条件跳转了,所以,JMP以上的代码与 CALL 无关;

    因此,CALL 的参数应该是JMP向下,直到CALl

    给参数起始位置设置断点,因为中间包含JE跳转,为了防止跳转,同时给JE也设置断点,重载并运行程序;

  5. 这里的戏就很精彩了,程序中断在参数位置:

    程序中断在参数位置

    然后按下Ctrl + A分析程序,在信息窗口发现跳转至此处的位置太多,如果挨个儿去跟,那就相当精彩了;

    同时,EAX 中有一个操作码OA,为啥它是操作码?因为根据 P-Code 的惯例,接下来既然要获取参数了,且代码没有执行,那 EAX 中存放的就是上一步的结果,而 P-Code 的逻辑就是先获取操作码,紧接着就是获取参数,那就说明,接下来获取的参数既是 CALL 的参数,也是OA操作码的参数,So,OA肯定是一个操作码;

    数据窗口跟随 ESI,发现OA位于当前 ESI 之前,地址是:401AD2;

    数据窗口跟随 ESI

    既然接下来要执行 CALL 也就是rtcMsgBox函数了,那么OA在 P-Code 中是否就是rtcMsgBox呢?

  6. 继续运行程序,直到将要获取下一个操作码:

    将要获取下一个操作码

    标志性的获取操作码的语句,接下来要获取的操作码是36,同时也反向说明,在这行代码之前,OA操作码是一直有效的;

    而且,OA的参数是两个:

    OA 的参数是两个

    因为操作了两次 ESI,同时,位于OA36之间的数据被分别放入了 ECX 和 EDI;

  7. 大胆的猜测一下,如果OA就是rtcMsgBox,那么替换它是否就能跳过弹窗呢?

  8. 重载程序,在数据窗口 goto 到OA,也就是 401AD2:

    goto 到 OA

  9. 打开opcode.txt,发现07OA参数数量和参数大小都相同,且07没有副作用:

    opcode.txt

    如上图所示:

    • OA表示调用指针(ptr)指向的函数,且没有返回值,4 字节大小,有 2 个参数,参数一 2 字节,参数二 2 字节(4 2 2 2);
    • 07表示 PUSH 值到堆栈,4 字节大小,有 2 个参数,参数一 2 字节,参数二 2 字节(4 2 2 2);

    这里不用 0B替换OA的原因是:CALL 的副作用要比 PUSH 大的多;

    所以,替换0A07

    替换 OA

    需要注意的是:替换操作码时,两个操作码的参数数量和参数大小必须完全相同,且替换的操作码对程序的运行没有副作用;

  10. 然后运行程序:

    然后运行程序

    没有出现 NAG 窗口,直接显示程序主窗体;

  11. 保存修改到可执行文件,运行程序:

    保存修改到可执行文件

    修改依然没有问题,完工!