自制反汇编逆向分析工具 迭代第六版本 (四)
本工具从最初版的跳转分布图只为了更直观地分析反汇编代码的分支结构,第三版开始对直观图进行逆向分支代码的输出,第四版对分支输出策略的一些探索,第五版结合之前的探索进行改进。第六版在现在功能的基础上进行增强,利用第六版(一)的基本功能-直译,第六版(二)对条件分支增加条件判断翻译,以及改进在函数调用处附带备选参数参考。
本篇是(四),在(三)的基础上增加对原子操作指令的逆向以及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::prepare_commit { // 0 pushq %rbp // 1 rbp = rsp; // 4 pushq %r15 // 6 pushq %r14 // 8 pushq %r13 // 10 pushq %r12 // 12 pushq %rbx // 13 rsp = rsp - 0x1058; // 20 r15 = rsi; // 23 _1078 = r15; // 30 r14 = rdi; // 33 rax = (void *)0x00000001066f9070: __stack_chk_guard; // 40 rax = rax->_0; // 43 _30 = rax; // 47 rsi = &_1030; // 54 edi = 0x400; // 59 edx = 0x1000; // 64 call x_heap_new_with_ptr; // 69 rbx = rax; // 72 _1080 = rbx; // 79 rdi = r15; // 82 call CA::Transaction::lock(); // 87 xmm0 = 0.; ; // 90 ((float*)&_1070)[0] = xmm0.ps[0]; ((float*)&_1070)[1] = xmm0.ps[1]; ((float*)&_1070)[2] = xmm0.ps[2]; ((float*)&_1070)[3] = xmm0.ps[3]; ; // 97 _1060 = 0x0; // 108 _1058 = r15; // 115 _1050 = rbx; // 122 _1048 = 0x2; // 132 _1044 = 0x4; // 142 _1040 = 0x0; // 152 rsi = &_1070; // 159 rdi = r14; // 162 call ((CA::Layer*)r14)->collect_layers_((CA::Layer::CollectLayersData*)&_1070); // 167 rbx = _1070; // 174 rdi = r15; // 177 call CA::Transaction::unlock(); // 182 goto _f188; _b184: // from 403 _b184: // from 386 // 184 rbx = rbx->_8; _f188: // from 182 // 188 testq %rbx, %rbx // 191 if (!) { // 188 (0 == rbx) // 197 r12 = rbx->_0; // 200 r14 = r12->_10; // 205 testq %r14, %r14 // 208 if (!) { // 205 (0 == r14) // 214 rdi = r15; // 217 call CA::Transaction::lock(); // 222 rdi = r14; // 225 rsi = "contents"; // 232 call objc_msgSend(r14, "contents"); // 238 r13 = rax; // 241 testq %r13, %r13 // 244 if () { // 241 (0 == r13) // gen jmp 336 goto _f336; // 246 rdi = r13; // 249 call CFRetain; // 254 rdi = r15; // 257 call CA::Transaction::unlock(); // 262 rdi = r13; // 265 call CFGetTypeID; // 270 r15 = rax; // 273 call CGImageGetTypeID; // 278 cmpq %rax, %r15 } // 281 else if () { // 278 (r15 != rax) // gen jmp 346 goto _f346; } else { // 281 next // 283 rdi = r14; // 286 rsi = "_renderImageCopyFlags"; // 293 call objc_msgSend(r14, "_renderImageCopyFlags"); // 299 r14d = eax; // 302 r15 = _1078; // 309 rdi = r15; // 312 call CA::Context::current_colorspace((CA::Transaction*)r15); // 317 xmm0 = 0.; ; // 320 rdi = r13; // 323 rsi = rax; // 326 edx = r14d; // 329 call CA::Render::prepare_image((CGImage*)r13, (CGColorSpace*)rax, (unsigned int)r14d, (double)xmm0); // 334 goto _f369; _f336: // from 244 } // 336 // 336 rdi = r15; // 339 call CA::Transaction::unlock(); // 344 goto _f377; _f346: // from 281 // 346 rdi = r13; // 349 rsi = "CA_prepareRenderValue"; // 356 call objc_msgSend(r13, "CA_prepareRenderValue"); // 362 r15 = _1078; _f369: // from 334 // 369 rdi = r13; // 372 call CFRelease; _f377: // from 344 } // 377 // 377 cmpq $0x0, 0x98(%r12) // 386 if () // 377 (r12->_98 == 0x0) goto _b184; // 392 rdi = r12; // 395 rsi = r15; // 398 call ((CA::Layer*)r12)->prepare_animations((CA::Transaction*)r15); // 403 goto _b184; } // 408 // 408 rdi = _1080; // 415 call x_heap_free; // 420 rax = (void *)0x00000001066f9070: __stack_chk_guard; // 427 rax = rax->_0; // 430 cmpq -0x30(%rbp), %rax // 434 if () // 430 (rax != _30) goto _f475; // 436 rsp = rsp + 0x1058; // 443 popq %rbx // 444 popq %r12 // 446 popq %r13 // 448 popq %r14 // 450 popq %r15 // 452 popq %rbp // 453 ret return; _b454: // from 473 // 454 r14 = rax; // 457 rdi = r15; // 460 call CA::Transaction::unlock(); // 465 rdi = r14; // 468 call _Unwind_Resume; // 473 goto _b454; _f475: // from 434 // 475 call __stack_chk_fail; /***** * global variables * */ // 33 extern ent_off__0x7516a; movq 0x75142(%rip), %rax; (void *)0x00000001066f9070: __stack_chk_guard // 225 extern ent_off__0x6fa52; movq 0x6f96a(%rip), %rsi; "contents" // 286 extern ent_off__0x6fa12; movq 0x6f8ed(%rip), %rsi; "_renderImageCopyFlags" // 349 extern ent_off__0x6f6c2; movq 0x6f55e(%rip), %rsi; "CA_prepareRenderValue" // 420 extern ent_off__0x7516a; movq 0x74fbf(%rip), %rax; (void *)0x00000001066f9070: __stack_chk_guard }
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 }