一个古老软件工具的逆向重生
一个古老软件工具的逆向重生
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小时。
一个古老软件工具的逆向重生相关推荐
- 汉诺塔(又称河内塔)问题是源于印度一个古老传说的益智玩具。
import java.math.BigInteger; /* * 汉诺塔(又称河内塔)问题是源于印度一个古老传说的益智玩具. 大梵天创造世界的时候做了三根金刚石柱子,在一根柱子上从下往上按照大小顺序 ...
- 转:一个古老的编程游戏:Python Challenge全通攻略
Python Challenge是一个网页闯关游戏,通过一些提示找出下一关的网页地址.与众不同的是,它是专门为程序员设计的,因为大多数关卡都要编程来算哦!! 去年和同学一起玩的,他做了大半,我做了小半 ...
- 机器人正在玩一个古老的基于DOS的游戏。
机器人正在玩一个古老的基于DOS的游戏.游戏中有N+1座建筑--从0到N编号,从左到右排列.编号为0的建筑高度为0个单位,编号为i的建筑的高度为H(i)个单位. 起初, 机器人在编号为0的建筑处.每一 ...
- 一个古老的编程游戏:Python Challenge全通攻略
一个古老的编程游戏:Python Challenge全通攻略 一个古老的编程游戏:Python Challenge全通攻略 - JimLiu - 博 posted on 2012-06-25 10:4 ...
- 机器人正在玩一个古老的基于DOS的游戏
机器人正在玩一个古老的基于DOS的游戏.游戏中有N+1座建筑--从0到N编号,从左到右排列.编号为0的建筑高度为0个单位,编号为i的建筑的高度为H(i)个单位. 起初, 机器人在编号为0的建筑处.每一 ...
- 一个古老故事--线程和线程池的故事
我是一个线程, 我一出生就被编了个号: 0×3704, 然后被领到一个昏暗的屋子里, 这里我发现了很多和我一模一样的同伴. 我身边的同伴0×6900 待的时间比较长, 他带着沧桑的口气对我说: 我们线 ...
- Android 逆向笔记 —— 一个简单 CrackMe 的逆向总结
温馨提示 请拖动到文章末尾,长按识别「抽奖」小程序. 在我的印象中,懂逆向的,都是大牛,让我们一起来看看下面这位大牛的学习心得. 无意中在看雪看到一个简单的 CrackMe 应用,正好就着这个例子总结 ...
- 一个古老的问题HashMap与Hashtable区别
HashTable的应用非常广泛,HashMap是新框架中用来代替HashTable的类,也就是说建议使用HashMap,不要使用HashTable.可能你觉得HashTable很好用,为什么不用呢? ...
- (转)一个古老的编程游戏:Python Challenge全通攻略
为什么80%的码农都做不了架构师?>>> Python Challenge是一个网页闯关游戏,通过一些提示找出下一关的网页地址.与众不同的是,它是专门为程序员设计的,因为大多数 ...
最新文章
- 关于Visual Studio2019的4996错误警告解决方法
- linear,swizzle,tile
- webservice、WSDL简介
- 分布式计算Hadoop系列之如何Eclipse中构建Hadoop项目
- FastReport使用方法(C/S版)
- Url有值怎么使用get传值
- brew 安装php7.1.6_mac上通过brew安装php7
- 【python】os 模块使用笔记
- 再谈UDP协议—浅入理解深度记忆
- Fedora 14常规娱乐软件
- 利用rsyslog 对Linux用户进行审计
- Spring Cloud Bus消息总线(学习总结)
- PHP字符串转换函数
- 如何在CSS中解决长英文单词的页面显示问题?CSS3
- 网络安全——Burpsuite
- 你所不了解的DevOps
- ZynqMP Vitis PS加载PL代码
- Maven打包依赖将依赖的Jar包也打进去
- grep egrep命令中-w选项的用法
- 北京2008年第29届奥运会吉祥物五个福娃(组图)