一个古老软件工具的逆向重生

2018/7/9

1. 背景

XXX是一个用于收集和分析映像文件信息的小工具,其开发时间大约在2001年,现在不能在WIN7下运行。

但是,当前项目仍需要使用该工具。因此,试图通过逆向分析后使之重生。

XXX的运行环境是win32。

2. 逆向分析

用IDA生成XXX的C程序,基本情况如下:

• 原始编译器是GNU C++。

• 12348物理行C代码。

• 共有252个函数(其中2函数反编译失败),其中绝大部分是C库函数。

• 所有函数复原了原始的符号名称。

• 大部分全局变量复原了原始的符号名称。

• 使用了lex生成词法分析代码,但没有lex的源文件。

总之,该工具的代码不难理解。

3. 修改

3.1. 预处理

用自己开发的IDA_Assistant对IDA生成的C程序进行修剪处理。

3.2. 删除C库函数

开始只删除熟知的库函数,如printf等。后来发现,在main函数后面的都是库函数,就一起删除了。

库函数的全局变量与应用程序的全局变量混在一起,只能经过确认后予以删除。

3.3. 复原lex代码

YY_BUFFER_STATE是lex中的一个重要数据结构,但IDA的反编译结果中没有这个结构,对这个数据结构的操作变成了意义不明的数组操作或指针操作。以下是函数yy_scan_buffer的反编译结果:

_DWORD *__cdecl yy_scan_buffer(int a1, unsigned int a2)

{

_DWORD *v2; // ebx

if ( a2 <= 1 || *(_BYTE *)(a2 + a1 - 2) || *(_BYTE *)(a2 + a1 - 1) )

return 0;

v2 = yy_flex_alloc(0x28u);

if ( !v2 )

yy_fatal_error(8148);

v2[1] = a1;

v2[3] = a2 - 2;

v2[2] = a1;

v2[5] = 0;

*v2 = 0;

v2[4] = a2 - 2;

v2[6] = 0;

v2[7] = 1;

v2[8] = 0;

v2[9] = 0;

yy_switch_to_buffer((int)v2);

return v2;

}

变量v2的类型应是YY_BUFFER_STATE,

对v2的赋值应是对结构分量的赋值,

因此要修改为:

v2->yy_buf_pos = a1;

v2->yy_buf_size = a2 - 2;

v2->yy_ch_buf =a1;

v2->yy_is_our_buffer = 0;

v2->yy_input_file = 0;

v2->yy_n_chars = a2 - 2;

v2->yy_is_interactive = 0;

v2->yy_at_bol = 1;

v2->yy_fill_buffer = 0;

v2->yy_buffer_status = 0;

3.4. 复原lex数据

lex生成的代码中有大量数据,其类型是short或int数据,但IDA把它们都翻译为int变量或int数组。例如:

int yy_chk = 0; // weak

int yy_nxt[40] =

{

2293760,

786452,

//以下略

};

实际应该是:

short int yy_chk[80] = {

0, 0, 0x20, 0x2B, 0x20, 2, 2, 0xD, 0x13, 2, 2, 2, 0x15, 0x16, 0x17, 0x13,

0x18, 0x16, 0xD, 0x15, 0x17, 0x19, 0x1C, 0x18, 0x1A, 0x1B, 0x1D, 0x1E, 0x2A, 0x29, 0x28, 0x1F,

0x27, 0x1C, 0x26, 0x19, 0x1E, 0x1A, 0x1D, 0x1F, 0x1B, 0x24, 0x24, 0x24, 0x2C, 0x25, 0x2C, 0x21,

0x12, 0x11, 0x0F, 0x0E, 0x0C, 0x03, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23,

0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0xB48D, 0x26, 0x0, 0x8D00, 0x27BC, 0, 0,

};

short int yy_nxt[80] =

{

0, 0x23, 0x14, 0xC, 0x21, 5, 5, 0xE, 0x14, 5, 5, 5, 0x14, 0x14, 0x14, 0x15,

0x14, 0x17, 0x0F, 0x16, 0x18, 0x14, 0x14, 0x19, 0x14, 0x14, 0x14, 0x14, 0xB, 0xA, 9, 0x14,

8, 0x1D, 7, 0x1A, 0x1F, 0x1B, 0x1E, 0x20, 0x1C, 4, 4, 4, 0x12, 6, 0x12, 0x22,

0x14, 0x13, 0x11, 0x10, 0x0D, 0x23, 3, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23,

0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x9090, 0x9090, 0x9090, 0x9090, 0x9090, 0x9090, 0x9090,

};

3.5. 辨别字符串

IDA的反编译结果中有许多如下语句:

yy_fatal_error(8148);

yy_fatal_error(8332);

从函数yy_fatal_error的定义获悉其输入参数应是字符串指针。经分析发现8148、8332实际是内存地址,8148对应16进制1FD4,在list文件中找到:

.text:00001FD4 aOutOfDynamicMe db 'out of dynamic memory in yy_scan_bu'

.text:00001FD4 db 'ffer()',0

.text:00001FFE align 10h

因此要改为:

yy_fatal_error(“out of dynamic memory in yy_scan_buffer()”);

3.6. 推导数据结构

根据XXX中的函数addFunc、getFunc、checkFunc、newFunc等,推导出以下数据结构定义:

typedef struct _func_info

{

int func_addr;

int func_kind;

char *func_name;

struct _func_info *next_func;

} func_info_t;

上述定义中的分量名根据代码中的全局变量名和代码的操作拟定的。例如,程序中有全局变量:

int address

int kind;

这两个变量出现在以下函数调用语句中:

v12 = newFunc(address, kind, v11);

在函数newFunc中address和kind赋给func_info_t的分量,因此可拟定分量名称。

3.7. 修改代码

IDA的反编译结果中有些代码令人费解,有些实际是错的,因此要予以纠正。

例如,反编译中有以下代码:

char byte_1129F[]; // weak

char nm_dir[]; // idb

if ( byte_1129F[strlen(nm_dir)] == 92 )

数组byte_1129F和nm_dir的定义中没有给出尺寸。在list文件中有:

.bss:0001129F ; char byte_1129F[]

.bss:0001129F byte_1129F db ?

.bss:000112A0 public _nm_dir

.bss:000112A0 ; char nm_dir[]

.bss:000112A0 _nm_dir dd ?

根据相邻变量的地址,可推导出byte_1129F有一个字节、nm_dir有272个字节,由此导出那行if语句应是:

if ( nm_dir[strlen(nm_dir)-1] == '\\' )

并且byte_1129F是不存在的。

3.8. 小结

完成上述工作后,源程序物理行数为1300。

然后在VS2010中编译、链接、生成可执行文件。

用这个逆向重生的可执行文件处理样例输入,产生与原始工具相同的输出。

本项任务历时两天,约10小时。

一个古老软件工具的逆向重生相关推荐

  1. 汉诺塔(又称河内塔)问题是源于印度一个古老传说的益智玩具。

    import java.math.BigInteger; /* * 汉诺塔(又称河内塔)问题是源于印度一个古老传说的益智玩具. 大梵天创造世界的时候做了三根金刚石柱子,在一根柱子上从下往上按照大小顺序 ...

  2. 转:一个古老的编程游戏:Python Challenge全通攻略

    Python Challenge是一个网页闯关游戏,通过一些提示找出下一关的网页地址.与众不同的是,它是专门为程序员设计的,因为大多数关卡都要编程来算哦!! 去年和同学一起玩的,他做了大半,我做了小半 ...

  3. 机器人正在玩一个古老的基于DOS的游戏。

    机器人正在玩一个古老的基于DOS的游戏.游戏中有N+1座建筑--从0到N编号,从左到右排列.编号为0的建筑高度为0个单位,编号为i的建筑的高度为H(i)个单位. 起初, 机器人在编号为0的建筑处.每一 ...

  4. 一个古老的编程游戏:Python Challenge全通攻略

    一个古老的编程游戏:Python Challenge全通攻略 一个古老的编程游戏:Python Challenge全通攻略 - JimLiu - 博 posted on 2012-06-25 10:4 ...

  5. 机器人正在玩一个古老的基于DOS的游戏

    机器人正在玩一个古老的基于DOS的游戏.游戏中有N+1座建筑--从0到N编号,从左到右排列.编号为0的建筑高度为0个单位,编号为i的建筑的高度为H(i)个单位. 起初, 机器人在编号为0的建筑处.每一 ...

  6. 一个古老故事--线程和线程池的故事

    我是一个线程, 我一出生就被编了个号: 0×3704, 然后被领到一个昏暗的屋子里, 这里我发现了很多和我一模一样的同伴. 我身边的同伴0×6900 待的时间比较长, 他带着沧桑的口气对我说: 我们线 ...

  7. Android 逆向笔记 —— 一个简单 CrackMe 的逆向总结

    温馨提示 请拖动到文章末尾,长按识别「抽奖」小程序. 在我的印象中,懂逆向的,都是大牛,让我们一起来看看下面这位大牛的学习心得. 无意中在看雪看到一个简单的 CrackMe 应用,正好就着这个例子总结 ...

  8. 一个古老的问题HashMap与Hashtable区别

    HashTable的应用非常广泛,HashMap是新框架中用来代替HashTable的类,也就是说建议使用HashMap,不要使用HashTable.可能你觉得HashTable很好用,为什么不用呢? ...

  9. (转)一个古老的编程游戏:Python Challenge全通攻略

    为什么80%的码农都做不了架构师?>>>    Python Challenge是一个网页闯关游戏,通过一些提示找出下一关的网页地址.与众不同的是,它是专门为程序员设计的,因为大多数 ...

最新文章

  1. 关于Visual Studio2019的4996错误警告解决方法
  2. linear,swizzle,tile
  3. webservice、WSDL简介
  4. 分布式计算Hadoop系列之如何Eclipse中构建Hadoop项目
  5. FastReport使用方法(C/S版)
  6. Url有值怎么使用get传值
  7. brew 安装php7.1.6_mac上通过brew安装php7
  8. 【python】os 模块使用笔记
  9. 再谈UDP协议—浅入理解深度记忆
  10. Fedora 14常规娱乐软件
  11. 利用rsyslog 对Linux用户进行审计
  12. Spring Cloud Bus消息总线(学习总结)
  13. PHP字符串转换函数
  14. 如何在CSS中解决长英文单词的页面显示问题?CSS3
  15. 网络安全——Burpsuite
  16. 你所不了解的DevOps
  17. ZynqMP Vitis PS加载PL代码
  18. Maven打包依赖将依赖的Jar包也打进去
  19. grep egrep命令中-w选项的用法
  20. 北京2008年第29届奥运会吉祥物五个福娃(组图)

热门文章

  1. 猫眼电影是怎么从美团网长出来的?
  2. uniapp h5 web-view不显示公众号文章
  3. ROS(1)创建工作空间和功能包过程
  4. 【HTML】三种加载动画
  5. python爬取文字和图片_Python学习第七天之爬虫的学习与使用(爬取文字、图片、 视频)...
  6. python opencv 调用摄像头失败问题的解决 Windows
  7. 积极应对APP风险问题,海云安力保移动应用安全
  8. 广东省揭阳市谷歌卫星地图下载
  9. Go实现json字符串与各类struct相互转换
  10. 面向对象方法学(2)