您的位置:首页 > 其它

自制反汇编逆向分析工具 迭代第六版本 (四)

2016-05-19 17:16 253 查看
本工具从最初版的跳转分布图只为了更直观地分析反汇编代码的分支结构,第三版开始对直观图进行逆向分支代码的输出第四版对分支输出策略的一些探索第五版结合之前的探索进行改进。第六版在现在功能的基础上进行增强,利用第六版(一)的基本功能-直译第六版(二)对条件分支增加条件判断翻译,以及改进在函数调用处附带备选参数参考

第六版(三)将(一)和(二)组合在一起进行逆向代码输出。

本篇是(四),在(三)的基础上增加对原子操作指令的逆向以及c++函数的逆向。

指令的原子操作如OSAtomic(Add|Xor|Or|And|CompareAndSwap),就是Lock锁总线后的指令操作。

下面说的是c++函数调用的逆向,主要如何套用参数。

c风格的函数和c++函数,在生成的函数符号上有区别。c风格的函数的符号不会有参数的任何信息,顶多就有参数的总大小(size),如msvc对extern "C" void test(int)可能生成 _test@4这样的符号。而c++风格的符号则会带上函数原型的全面信息,如属于哪个类哪个名字空间参数序列几何,这样才能够使c++在相同的函数名可以被重载,符号连接才不会冲突。所以在调试器反汇编出来的代码,往往可以提示出c++函数的原型,而c风格的函数只有名字(不能解析参数序列)。

既然调试器反汇编出了c++函数符号,就应该好好使用。但调试器并没有提示一个类的函数是静态成员函数还是成员函数,因为这两种函数在调用约定时,相差了一个参数位,所以在逆向分析时要进行分析区分。一般来说,构造和析构函数一定是成员函数,static和const修饰不同时使用,带const修饰就可以认为也是成员函数。剩下来的就只能够通过分析判断。

我的方法是将类方法同时分别去应用两种调用约定(不带this的静态成员函数调用和带this的成员函数调用),然后分别对两种情况下寄存器使用的匹配度进行比较,判断出其中的一种。不像hopper那样,将明明是c++的类方法,却当作c风格函数来简单处理。

下面是对CA::Render::key_path_set(void**, __CFString const*)调用的分析判断,判断结果是成员函数参数序列不相符,所以应当是静态成员函数。

// 64    rdi = &_30;
// 68    rsi = r12;
// 71 call
// CA::Render::key_path_set((void**)&_30, (__CFString const*)r12);
// ((CA::Render*)&_30)->key_path_set((void**)r12, (__CFString const*)rdx/*wrong*/);
CA::Render::key_path_set(void**, __CFString const*);
// 76    rdi = r15;
// 79 call
CA::Transaction::lock();
// 84    r15 = r14->_98;
// 91    rbx = r14;
// 94    _38 = r15;
// 98 testq %r15, %r15
// 101
if (!) { // 98 (0 == r15)
// 103    r13 = &_38;
// 107    r12d = 0;
// 110    r14 = &_30;
_b114:     // from 174
// 114    rsi = &r15->_10;
// 118    edx = 0;
// 120    rdi = r14;
// 123 call
// CA::Render::key_path_equal((void* const*)r14, (void* const*)&r15->_10, (bool)0);
// ((CA::Render*)r14)->key_path_equal((void* const*)&r15->_10, (void* const*)rdx/*wrong*/, (bool)cl/*wrong*/);
CA::Render::key_path_equal(void* const*, void* const*, bool);


再来看

if (!) { // 738 (0 == r12)
// 751    rdi = r12;
// 754 call
((CA::Render::Object*)r12)->unref();
_f759:     // from 714
} // 759
// 759    rsi = _38;
// 763    rdi = r13;
// 766 call
// CA::Layer::set_animations((CA::Layer::Animation*)r13);
// ((CA::Layer*)r13)->set_animations((CA::Layer::Animation*)_38);
CA::Layer::set_animations(CA::Layer::Animation*);
// 771    edx = 0x1;
// 776    rdi = r13;
// 779    rsi = r14;
// 782 call
// CA::Layer::mark_animations((CA::Transaction*)r13, (bool)esi/*wrong*/);
// ((CA::Layer*)r13)->mark_animations((CA::Transaction*)r14, (bool)0x1);
CA::Layer::mark_animations(CA::Transaction*, bool);
// 787    rdi = r14;
// 790 call
CA::Transaction::unlock();


首先是CA::Render::Object::unref() const,可以确定这是一个成员函数,所以使用成员函数调用方式。

接着是CA::Layer::set_animations(CA::Layer::Animation*), 两种方式的假设都没有找出不符,优先使用成员成员函数方式。

第三是CA::Layer::mark_animations(CA::Transaction*, bool),静态成员方式调用匹配有不符,所以可以判定是成员函数。

下面是贴上两个函数的逆向输出:

CA::Layer::update_removed_sublayer
{
// 0 pushq %rbp
// 1    rbp = rsp;
// 4 pushq %r14
// 6 pushq %rbx
// 7    r14 = rsi;
// 10    rbx = rdi;
// 13    rbx->_8 = 0x0;
// 21    rbx->_a4 = edx;
// 27    edx = 0;
// 29 call
// CA::Layer::mark_visible((CA::Transaction*)rdi, (bool)esi);
// ((CA::Layer*)rdi)->mark_visible((CA::Transaction*)rsi, (bool)0);
CA::Layer::mark_visible(CA::Transaction*, bool);
// 34    rdi = r14;
// 37    rsi = rbx;
// 40 call
((CA::Transaction*)r14)->add_root((CA::Layer*)rbx);
// 45 lock
// 46    OSAtomicAnd32(0xffefffff, (volatile int32_t*)&rbx->_4);
// 53    rbx->_84 = rbx->_84 & 0xffffbfff;
// 60    eax = rbx->_80;
// 66    eax = eax << 0x3;
// 69    eax = eax ^ rbx->_4;
// 72 testl $0x400000, %eax
// 77
if () // 72 (0x400000 & eax)
goto _f84;
// 79 popq %rbx
// 80 popq %r14
// 82 popq %rbp
// 83 ret
return;
_f84:     // from 77
// 84    rdi = rbx;
// 87    rsi = r14;
// 90 popq %rbx
// 91 popq %r14
// 93 popq %rbp
// 94 ret
return;    // jmp 0x1041aa814; CA::Layer::toggle_flipped(CA::Transaction*)
// 99 nop
}


CA::Layer::update_removed_sublayer
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: