原文地址:Question about disassembler

简介

这篇文章介绍了如何在不使用插件的IDA Hex-Rays如何得到比较清晰的伪代码。IDA Hex-Rays功能很强大,只要你提供了足够多的信息,它就能产生十分简单明了的代码。

下面我们以下面这个二进制文件为例:

为了方便我直接把exe文件后缀改成jpg,下载下来把文件后缀改回exe就行了

二进制文件下载地址:

步骤

打开IDA Pro加载这个exe文件,先按shitf + F5,添加vc32_14, vc32rtf, vc32ucrt这三个符号签名文件。

这个exe文件的main函数不太好找,我们先定位到exe文件的入口,按F5得到以下结果

signed int __usercall start@<eax>(int a1@<ebp>, int a2@<esi>)
{char v2; // blint v4; // ST14_4_DWORD *v5; // eax_DWORD *v6; // esi_DWORD *v7; // eax_DWORD *v8; // esiconst char **v9; // ediint *v10; // esiconst char **v11; // eaxsub_4018B4();if ( !(unsigned __int8)__scrt_initialize_crt(1)|| (v2 = 0, *(_BYTE *)(a1 - 25) = 0, *(_DWORD *)(a1 - 4) = 0, *(_BYTE *)(a1 - 36) = sub_401631(), dword_41CC40 == 1) ){__scrt_fastfail(7);goto LABEL_20;}if ( dword_41CC40 ){v2 = 1;*(_BYTE *)(a1 - 25) = 1;}else{dword_41CC40 = 1;if ( _initterm_e(&unk_415140, &unk_415158) ){*(_DWORD *)(a1 - 4) = -2;return 255;}_initterm(&unk_415134, &unk_41513C);dword_41CC40 = 2;}__scrt_release_startup_lock(*(_DWORD *)(a1 - 36));v5 = (_DWORD *)sub_40196C(v4);v6 = v5;if ( *v5 ){if ( (unsigned __int8)__scrt_is_nonwritable_in_current_image(v5) )((void (__thiscall *)(_DWORD, _DWORD, signed int, _DWORD))*v6)(*v6, 0, 2, 0);}v7 = (_DWORD *)sub_401972();v8 = v7;if ( *v7 ){if ( (unsigned __int8)__scrt_is_nonwritable_in_current_image(v7) )_register_thread_local_exe_atexit_callback(*v8);}v9 = *(const char ***)sub_406ACE();v10 = (int *)sub_406AC8();v11 = (const char **)unknown_libname_31();a2 = main(*v10, v9, v11);if ( !(unsigned __int8)sub_401A94() )
LABEL_20:exit(a2);if ( !v2 )_cexit();__scrt_uninitialize_crt(1, 0);*(_DWORD *)(a1 - 4) = -2;return a2;
}

注意下面的代码

  a2 = main(*v10, v9, v11);if ( !(unsigned __int8)sub_401A94() )
LABEL_20:exit(a2);

exit函数的参数应该就是主函数的返回值。

定位到到main函数

.text:00401390                 mov     esi, eax
.text:00401392                 call    sub_406312
.text:00401392
.text:00401397                 push    eax             ; envp
.text:00401398                 push    edi             ; argv
.text:00401399                 push    dword ptr [esi] ; argc
.text:0040139B                 call    main

按F5,我们会得到以下代码

int __cdecl main(int argc, const char **argv, const char **envp)
{HMODULE v3; // esiCHAR v4; // alint v5; // ecxunsigned int v6; // esichar v7; // bl__int128 v9; // [esp+4h] [ebp-22Ch]int v10; // [esp+14h] [ebp-21Ch]int v11; // [esp+18h] [ebp-218h]__int16 v12; // [esp+1Ch] [ebp-214h]char v13; // [esp+1Eh] [ebp-212h]int v14; // [esp+20h] [ebp-210h]char v15; // [esp+24h] [ebp-20Ch]CHAR Buffer[256]; // [esp+124h] [ebp-10Ch]int v17; // [esp+224h] [ebp-Ch]char v18; // [esp+228h] [ebp-8h]v3 = GetModuleHandleA(0);memset(Buffer, 0, 0xFFu);memset(&v15, 0, 0xFFu);if ( !LoadStringA(v3, 0x539u, Buffer, 255) )return -1;v4 = Buffer[0];if ( Buffer[0] ){v5 = 0;do{*((_BYTE *)&v14 + ++v5 + 3) = v4 ^ 0x30;v4 = Buffer[v5];}while ( v4 );}memset(Buffer, 0, 0xFFu);if ( !LoadStringA(v3, 0x29Au, Buffer, 255) )return -1;v17 = 0;v18 = 0;v14 = 5;if ( RegGetValueA(-2147483647, &v15, Buffer, 0xFFFF, 0, &v17, &v14) )return -1;v6 = 0;v9 = xmmword_4194E0;v10 = 55858812;v7 = 114;v11 = 1157851502;v12 = 20051;v13 = 0;do{sub_401010((const char *)&unk_4194D0, v7 ^ *((_BYTE *)&v17 + v6 % (v14 - 1)));v7 = *((_BYTE *)&v9 + v6++ + 1);}while ( v7 );return 0;
}

看起来确实很乱,但我们可以帮助反汇编器给出一个稍好一点的代码

首先我们有两个memsets

  memset(Buffer, 0, 0xFFu);memset(&v15, 0, 0xFFu);

Buffer和v15的原型应该是char name[0xFF]。点击Buffer然后按y键,把Buffer的类型改成char name[0xFF],对v15做同样的事即可。

此外我们可以给这些变量一个有意义一点的名字,例如buffer_1和buffer_2。点击变量,按n键即可修改变量的名字。

通过查看unk_4194D0我们会发现它是%c,那么sub_401010这个函数应该就是printf函数了,重命名sub_401010printf,把printf的函数原型改成int printf(const char *format, ...)

LoadStringARegGetValueA里的数字通过按H键转换成十六进制,这样子看起来方便些,然后把其他的一些变量名也改成有意义的字符。

这样子我们就得到下面的代码了:

int __cdecl main(int argc, const char **argv, const char **envp)
{HMODULE cur_proc; // esichar byte; // alint i; // ecxunsigned int cou; // esichar xor_byte; // bl__int128 xored_flag; // [esp+4h] [ebp-22Ch]int part_of_xored_flag; // [esp+14h] [ebp-21Ch]int part_of_xored_flag_1; // [esp+18h] [ebp-218h]__int16 part_of_xored_flag_2; // [esp+1Ch] [ebp-214h]char part_of_xored_flag_3; // [esp+1Eh] [ebp-212h]int some_buff; // [esp+20h] [ebp-210h]char buff_2[255]; // [esp+24h] [ebp-20Ch]char buff_1[255]; // [esp+124h] [ebp-10Ch]int xor_key_buff; // [esp+224h] [ebp-Ch]char v18; // [esp+228h] [ebp-8h]cur_proc = GetModuleHandleA(0);memset(buff_1, 0, 0xFFu);memset(buff_2, 0, 0xFFu);if ( !LoadStringA(cur_proc, 1337u, buff_1, 255) )return -1;byte = buff_1[0];if ( buff_1[0] ){i = 0;do{*((_BYTE *)&some_buff + ++i + 3) = byte ^ 0x30;byte = buff_1[i];}while ( byte );}memset(buff_1, 0, 0xFFu);if ( !LoadStringA(cur_proc, 666u, buff_1, 255) )return -1;xor_key_buff = 0;v18 = 0;some_buff = 5;if ( RegGetValueA(0x80000001, buff_2, buff_1, 0xFFFF, 0, &xor_key_buff, &some_buff) )return -1;cou = 0;xored_flag = xmmword_4194E0;part_of_xored_flag = 0x354567C;xor_byte = 0x72;part_of_xored_flag_1 = 0x4503696E;part_of_xored_flag_2 = 0x4E53;part_of_xored_flag_3 = 0;do{printf("%c", xor_byte ^ *((char *)&xor_key_buff + cou % (some_buff - 1)));xor_byte = *((_BYTE *)&xored_flag + cou++ + 1);}while ( xor_byte );return 0;
}

看起来清爽了一点,但还是有点乱。

下面我们看看能对``some_buff做些什么,双击some_buff我们会跳转到栈视图。

-0000022C xored_flag      db ?
-0000022B                 db ? ; undefined
-0000022A                 db ? ; undefined
-00000229                 db ? ; undefined
-00000228                 db ? ; undefined
-00000227                 db ? ; undefined
-00000226                 db ? ; undefined
-00000225                 db ? ; undefined
-00000224                 db ? ; undefined
-00000223                 db ? ; undefined
-00000222                 db ? ; undefined
-00000221                 db ? ; undefined
-00000220                 db ? ; undefined
-0000021F                 db ? ; undefined
-0000021E                 db ? ; undefined
-0000021D                 db ? ; undefined
-0000021C                 db ? ; undefined
-0000021B                 db ? ; undefined
-0000021A                 db ? ; undefined
-00000219                 db ? ; undefined
-00000218                 db ? ; undefined
-00000217                 db ? ; undefined
-00000216                 db ? ; undefined
-00000215                 db ? ; undefined
-00000214                 db ? ; undefined
-00000213                 db ? ; undefined
-00000212                 db ? ; undefined
-00000211                 db ? ; undefined
-00000210 some_buff       dd ?            ; <<<<< our variable
-0000020C buff_2          db 255 dup(?)
-0000010D                 db ? ; undefined
-0000010C buff_1          db 255 dup(?)
-0000000D                 db ? ; undefined
-0000000C xor_key_buff    db ?
-0000000B                 db ? ; undefined
-0000000A                 db ? ; undefined
-00000009                 db ? ; undefined

some_buff是dword或者四个字节,那他应该是一个字符buff,把它的类型改成char a[4]

然后把xor_key_buff的类型设置为char a[4]xored_flag设置为char a[28]buff_1 and buff_2设置为char a[256]

我们就有下面的栈视图了

-0000022C xored_flag      db 28 dup(?)
-00000210 some_buff       db 4 dup(?)
-0000020C buff_2          db 256 dup(?)
-0000010C buff_1          db 256 dup(?)
-0000000C xor_key_buff    db 4 dup(?)

再点下F5刷新伪代码视图,我们会得到以下主函数伪代码:

int __cdecl main(int argc, const char **argv, const char **envp)
{HMODULE cur_proc; // esichar byte; // alint i; // ecxunsigned int cou; // esichar xor_byte; // blchar xored_flag[28]; // [esp+4h] [ebp-22Ch]char some_buff[4]; // [esp+20h] [ebp-210h]char buff_2[256]; // [esp+24h] [ebp-20Ch]char buff_1[256]; // [esp+124h] [ebp-10Ch]char xor_key_buff[4]; // [esp+224h] [ebp-Ch]char v14; // [esp+228h] [ebp-8h]cur_proc = GetModuleHandleA(0);memset(buff_1, 0, 0xFFu);memset(buff_2, 0, 0xFFu);if ( !LoadStringA(cur_proc, 1337u, buff_1, 255) )return -1;byte = buff_1[0];if ( buff_1[0] ){i = 0;do{some_buff[++i + 3] = byte ^ 0x30;byte = buff_1[i];}while ( byte );}memset(buff_1, 0, 0xFFu);if ( !LoadStringA(cur_proc, 666u, buff_1, 255) )return -1;*(_DWORD *)xor_key_buff = 0;v14 = 0;*(_DWORD *)some_buff = 5;if ( RegGetValueA(0x80000001, buff_2, buff_1, 0xFFFF, 0, xor_key_buff, some_buff) )return -1;cou = 0;*(_OWORD *)xored_flag = xmmword_4194E0;*(_DWORD *)&xored_flag[16] = 0x354567C;xor_byte = 0x72;*(_DWORD *)&xored_flag[20] = 0x4503696E;*(_WORD *)&xored_flag[24] = 0x4E53;xored_flag[26] = 0;do{printf("%c", xor_byte ^ xor_key_buff[cou % (*(_DWORD *)some_buff - 1)]);xor_byte = xored_flag[cou++ + 1];}while ( xor_byte );return 0;
}

现在点击RegGetValueA里的0x80000001

if ( RegGetValueA(0x80000001, buff_2, buff_1, 0xFFFF, 0, xor_key_buff, some_buff) )

按M选择枚举值HKEY_CURRENT_USER

最后的代码就是这个样子了

int __cdecl main(int argc, const char **argv, const char **envp)
{HMODULE cur_proc; // esichar byte; // alint i; // ecxunsigned int cou; // esichar xor_byte; // blchar xored_flag[28]; // [esp+4h] [ebp-22Ch]char some_buff[4]; // [esp+20h] [ebp-210h]char buff_2[256]; // [esp+24h] [ebp-20Ch]char buff_1[256]; // [esp+124h] [ebp-10Ch]char xor_key_buff[4]; // [esp+224h] [ebp-Ch]char v14; // [esp+228h] [ebp-8h]cur_proc = GetModuleHandleA(0);memset(buff_1, 0, 0xFFu);memset(buff_2, 0, 0xFFu);if ( !LoadStringA(cur_proc, 1337u, buff_1, 255) )return -1;byte = buff_1[0];if ( buff_1[0] ){i = 0;do{some_buff[++i + 3] = byte ^ 0x30;byte = buff_1[i];}while ( byte );}memset(buff_1, 0, 0xFFu);if ( !LoadStringA(cur_proc, 666u, buff_1, 255) )return -1;*xor_key_buff = 0;v14 = 0;*some_buff = 5;if ( RegGetValueA(HKEY_CURRENT_USER, buff_2, buff_1, 0xFFFF, 0, xor_key_buff, some_buff) )return -1;cou = 0;*xored_flag = g_xored_flag;*&xored_flag[16] = 0x354567C;xor_byte = 0x72;*&xored_flag[20] = 0x4503696E;*&xored_flag[24] = 0x4E53;xored_flag[26] = 0;do{printf("%c", xor_byte ^ xor_key_buff[cou % (*some_buff - 1)]);xor_byte = xored_flag[cou++ + 1];}while ( xor_byte );return 0;
}

转载于:https://www.cnblogs.com/Antiver/p/10189055.html

IDA Pro - 如何得到比较清楚的逆向伪代码相关推荐

  1. ida 反编译 linux bin,使用IDA pro逆向ARM M系核心的Bin固件

    物联网和智能设备这两年还是比较火的,我们的手中或多或少都有了几个智能设备,比如手环,智能手表,或者门锁什么之类的东西,但是同学们在做逆向的时候,却有很多问题.要不然是根本拿不到固件,要不然是拿到了Bi ...

  2. IDA Pro逆向实战之Crackme(简单篇)

    IDA Pro逆向实战之Crackme(简单篇) 今天手闲的很,没事就拿出了以前没解决的逆向题来做一下,具体的源程序在附件里,废话少说,直接上菜: 0.   源程序运行效果(输入不对的,直接退出): ...

  3. Windows破解逆向-CrackMe_1实例(使用IDA Pro修改静态区资源)

    这里开发了一个CrackMe实例,源码打包下载如下: https://github.com/fengfanchen/Qt/tree/master/CrackMe_1 程序是这个样子的: 程序从10s开 ...

  4. 浅谈安卓逆向协议(四)- ida pro - 小红书

    文章仅提供思路,千里之行,还要靠各位自己努力,不喜勿看. 重头戏-小红书.这是相比前几个最难的了.为什么?看下面娓娓道来. 小红书互联网上真是没搜到解决方案,主要是sign验签和shield验签,si ...

  5. android 逆向ida,浅谈安卓逆向协议(四)- ida pro - 小红书

    文章仅提供思路,千里之行,还要靠各位自己努力,不喜勿看. 重头戏-小红书.这是相比前几个最难的了.为什么?看下面娓娓道来. 小红书互联网上真是没搜到解决方案,主要是sign验签和shield验签,si ...

  6. CTF逆向-IDA Pro攻防世界Hello CTF

    文章目录 前言 Hello CTF IDA反汇编 Flag值计算 总结 前言 交互式反汇编器专业版(Interactive Disassembler Professional),人们常称其为 IDA ...

  7. IDA pro逆向工具寻找socket server的IP和port

    在逆向分析代码的时候,我们有时需要找到某软件做服务端时提供的ip:port. 使用IDA pro反编译代码,找到套接字设置的代码处,发现我们期待的IP和port的地方是数字 这时我们该怎么办呢? 第一 ...

  8. [免费专栏] Android安全之静态逆向APK应用浅析「手动注入smali」+「IDA Pro静态分析so文件」+「IDA Pro基础使用讲解」

    也许每个人出生的时候都以为这世界都是为他一个人而存在的,当他发现自己错的时候,他便开始长大 少走了弯路,也就错过了风景,无论如何,感谢经历 Android安全付费专栏长期更新,本篇最新内容请前往: [ ...

  9. python反编译luac_Lua程序逆向之为Luac编写IDA Pro文件加载器

    距离上一次讲Lua程序逆向已经有一段时间了,这一次我们书接上回,继续开启Lua程序逆向系列之旅. 在软件逆向工程实践中,为第三方文件编写文件格式分析器与指令反汇编器是一种常见的场景.这一篇的主要目的是 ...

最新文章

  1. 前端每日实战:143# 视频演示如何用 CSS 的 Grid 布局创作一枚小松鼠邮票
  2. vue开发搭建(npm安装 + vue脚手架安装)
  3. python messagebox输出_python 3.4 中原来的tkinter组件的tkMessageBox变成啥了?
  4. spring boot2.x整合redis
  5. Python虚拟环境virtualenv的安装与使用详解(转)
  6. 服务器系统安装及部署pdf,服务器操作系统安装说明.pdf
  7. 十二月份找工作好找吗_学习完3D游戏建模好找工作吗
  8. CentOS 设置网络(修改IP修改网关修改DNS)
  9. Android游戏开发源码案例25个汇总
  10. linux数字版权管理,数字版权管理系统 DRM
  11. 51单片机——八段数码管
  12. 专家学者热议智慧交通:大数据云计算,出行有“千里眼”
  13. python123 第四次作业_第四次作业
  14. 关于esxtop命令下%RUN、%RDY和%MLMTD三个参数的详细解读
  15. mysql怎样添加一条数据_sql语句怎么添加一条记录?
  16. 路由懒加载的三种写法
  17. @ConfigurationProperties 与 @EnableConfigurationProperties
  18. POJ3614 [USACO07NOV]防晒霜Sunscreen
  19. 一文读懂谷歌I/O 新硬件、Android Q及多项功能升级
  20. 2023 车险计算器微信小程序源码

热门文章

  1. 五年之后的私有云和公有云会是什么样子
  2. iOS培训教程——创建第一级控制器
  3. mysql双机热备份的实现步骤
  4. 【Python-ML】SKlearn库线性回归器LinearRegression
  5. CNN in MRF: Video Object Segmentataion via Inference in A CNN-Based Higher-Order Spatio-Temporal MRF
  6. android中线程和进程
  7. 用java做出32选7_用java做的一个彩票32选7的简单程序
  8. js常用事件整理—兼容所有浏览器
  9. JS事件:target与currentTarget区别
  10. mysql实现汉字转拼音