环境搭建
仍然推荐使用虚拟机,本人5600X+32G的机器也感觉不到啥卡顿。
IDA PRO 的版本推荐 7.7,看雪上就有的下,是百度网盘的,傻逼百度。所以我传了一份夸克网盘,毕竟开淘宝88vip送的,不用白不用。两个链接都贴上,按需下载:
python 安装与设置
建议直接看下面的绿色安装部分
由于后面会涉及到脚本编写,所以也需要安装python,python 安装有两种,一种是安装到系统,一种是绿色版安装。
如果选择安装到系统 ,推荐按照 github.com/pyenv-win/p... 这个项目来搭建,非常的简单,三个命令就完事了。
第一条,使用管理员打开 powershell
,输入:
sql
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope LocalMachine
按照提示输入 A,反正是虚拟机,随便搞。
第二条,在 powershell
里面输入,安装pyenv-win
:
dart
Invoke-WebRequest -UseBasicParsing -Uri "https://raw.githubusercontent.com/pyenv-win/pyenv-win/master/pyenv-win/install-pyenv-win.ps1" -OutFile "./install-pyenv-win.ps1"; &"./install-pyenv-win.ps1"
安装完成后,新开一个 powershell
,输入:
css
pyenv --version
查看是否正确安装了。
第三条,安装 python 3.8.8 版本,可以随意选择,但是最好是 3.8.x 的,会比较稳定:
pyenv install 3.8.8
如果命令行下载不下来,可以自己找一个安装文件放到下载文件夹下面,在运行命令,就可以安装了。
安装完成后,查看已安装 python 版本,使用 pyenv versions
命令。
使用 pyenv global 3.8.8
设置当前 python 版本。
一切搞定之后,打开 ida pro,可以看到一个 python 窗口:
如果你仔细看下日志,会发现里面报了一些错误,这是因为这个 ida 里面自带了一些插件,而这些插件依赖了 python 的一些模块,所以我们还需要安装这些模块,IDA 里面有 readme 可以看看。
如果看不到 python 窗口,很大的可能是ida找不到python安装在了哪里,可以使用 ida 目录下的 idapyswitch.exe
来强制指定 python 安装目录:
css
idapyswitch.exe --force-path C:\Users\xxx.pyenv\pyenv-win\versions\3.8.8\python3.dll
然后设置一下环境变量:
创建新的用户变量PYTHONHOME
,路径为C:\Users\xxx.pyenv\pyenv-win\versions\3.8.8
在Path里创建新路径C:\Users\xxx.pyenv\pyenv-win\versions\3.8.8\Lib
绿色安装就没有上面这么多问题,因为 ida 目录下是有个 python38 版本的,依赖的模块已经存在了,就不需要再导入了。还是推荐使用绿色版的,不用装依赖模块。
不过发现即使点了 ida 目录下的 IDA_InitTool 初始化环境,但是打开 ida 的时候有个脚本还是会加载出错:
plugin initialization failed: Python interpreter not found
看了下 python 逻辑,发现它获取 python 路径的时候使用的固定的一些目录。比如 C 盘的 python 等等。所以我们只需要将 ida 的目录添加进去就好了:
这样就不会报错了,记得写绝对路径,发现打开ida,与加载待分析文件时会使用不同的相对路径比较坑。
示例分析
文件放到了 github.com/aprz512/And... 下。
先看看程序界面长什么样:
嗯,我们最终的目标肯定是攻破这个程序,但是作为开篇课,还是难了点,我们还是先来认识一下 IDA 吧。
一般情况下,不需要更改 IDA 打开时的默认选项
IDA 窗口
第一部分是函数窗口,这个非常重要,看它占据的位置就知道了。
IDA汇编窗口
第二部分是汇编代码窗口,注意上面的tab是 IDA viewA,还有很多其他的 tab 会显示在这块区域,我们后面都会涉及到。
我们现在看到的这个窗口,按空格键可以切换模式:
这个是文本模式,之前的是图形模式,两种模式各有优缺点。
图形模式可以按住滚轮来缩放,可以很清晰的看到函数控制流程。
文本模式可以看到指令地址,熟悉汇编的会更有感觉。
IDA 伪代码窗口
在汇编窗口,按 tab/F5 键,可以切换到伪代码窗口(切到伪代码窗口后想切换回来,只能使用tab,所以建议一直使用 tab 键):
在伪代码窗口,想要看某条语句对应的指令位置,将鼠标放到该语句上,然后按 tab 键即可。
IDA 字符串表
这个表是非常重要的,按 Shift + F12 可以直接打开,当然你也可以菜单打开 [View] -> [Open Subviews] -> [Strings]。
字符串表收集了 IDA 识别到的所有字符串(不一定齐全)。字符串信息是逆向工作中非常关键的信息,按下 Ctrl + F 弹出底部筛选器,筛选包含关键字的字符串(所有表格窗格均可,比如函数窗口)。
双击字符串会进去该字符串对应的数据区域:
IDA 的数据窗口
打开方式:菜单 [View] -> [Open subviews] -> [Hex dump],不过一般默认就是打开的。
这个窗口我们可以用来更改汇编指令,比如一些条件的反转之类的。F2 键 进入编辑模式,再次按下 F2 键退出编辑模式 (但是不推荐在数据窗口修改数据),按 Ctrl + Z 就可以撤销上一次的更改。
按 G 键跳转到指定的地址(亦可在反汇编/伪代码窗口使用),比如我们从错误堆栈里面得到了一个地址,就可以跳转到这个地址看看是出了什么问题。
IDA 的交叉引用
对于一些没有符号的函数,ida 会使用其地址加 sub_ 的方式来作为函数名,我们如果想要查看这个函数在哪里被引用到了,可以使用快捷键 X:
可以看到,这个函数被引用的地方有两个。
第一个地方是另外一个函数,第二个地方是一个偏移地址。
这个表格有4个子项:
- direction ,表示被引用的地方是在当前地址的前面还是后面
- Type,这个有点复杂,交叉引用分为代码交叉引用和数据交叉引用
-
- 读取交叉引用, 用 r 表示
- 写入交叉引用,用 w 表示
- 偏移量交叉引用,用 o 表示
- 普通流,用 o 表示
- 调用流,用 p 表示
- 跳转流,用 j 表示
- 代码交叉引用又分为
- 数据交叉引用
- Address,引用地址
- Text,引用地址处的反汇编文本
举个简单的例子:
arduino
void main() { printf("%s", abc); }
main 函数引用了 printf 、"%s"、abc,我们就可以通过 abc、printf、"%s" 交叉引用找到 main 函数。
案例分析
我们使用字符串窗口,找到程序中的字符串:
双击,找到字符串位置,按 X 键,找到引用这个字符串的位置:
点击 OK,跳转:
一般情况下,这里就是我们的 main 函数了。
需要注意的是,main 函数也是会被别的函数引用的,我们可以写一个最简单的例子,然后编译成 exe 文件,看其符号表,会发现有很多的函数名,这写函数就是用来在启动 main 函数之前做一些事情的。
不用太在意这里的玄学,我们主要学习的是 ida 的一些操作,对于函数的行为,使用 hook 来看会更严谨
接下来的部分,就需要一些经验,或者是说玄学了,我们可以看一下程序的行为,再看看这个方法里面的函数,发现 sub_140002996
这个函数就是用来将字符串显示到屏幕上的,那么我们就不需要看这个函数里面做了什么了!直接给他改个名字就跳过它,去看别的函数,按住 N 键即可改名:
改名后效果如下:
还有这个 sub_140001834
函数,它的一个参数是 %s,一个参数是一个 char[],所以大概率就是将用户输入的字符串存放到字符数组里面了,再重新命名一下函数:
显然,最后的这个 sub_140001596
函数就是校验用户名与密码了。
点到这个函数里面看看,一直点下去,将参数重命名一下:
红框部分,我们在 main 函数里面也见到过类似的,所以我们不用看它。
点击参数,看被使用到的位置,是在 if 逻辑里面,所以我们的关注核心是在 if 里面。这样的代码有点难看,我们可以右键 → hide cast,让代码看起来简洁点:
这段代码里面 sub_140002F90
先对 username 做了处理,看看里面:
1处的函数返回的值,用在了下面 if 的判断里面,判断这个值是否小于 100。
2处的是一个十六进制值,是一个边界条件,在这个十六进制右键可以将这个值转成其他形式,比如字符,十进制等:
所以猜测 一下,这里的返回值是 username 的长度。看到 else 条件会返回 0,所以 username 的长度不能超过 100,可以输入试试验证猜想。
3处的判断是在一个双重循环里面,根据上面的 v8 处的引用,qmemcpy 和 memcpy 比较像,先将它当作是一个memcpy来看,所以是 if 就是判断 username 里面有没有 @|;+-
这5个字符,有就返回0,我们也可以故意输入试试验证猜想。
我会再回到main函数,经过一些函数的重命名之后,代码好看了不少:
虽然都是靠猜测,但是只要符合我们的预期就行。
接下来就是要研究 sub_140002B67
这个函数:
看起来就很复杂,但是有经验的人一眼就能看出这是一个 base64 编码算法,其特征就是里面的 0x3F,0xF 等数值。戳一下 off_14013F000
:
我们可以看到这个地方储存了一个地址,值为 0140108F20,这个地址里面储存的东西是 aAbcdefghijklmn,我们点一下这字符串(这个字符串是ida自动生成的,规则暂时不清楚,可以看作是真实字符串的一个缩影):
发现,它就是一个base64 的编码表,还是一个原始版本的。
常用快捷键
a:将数据转换为字符串
f5/tab:一键反汇编
esc:回退键,能够倒回上一部操作的视图(只有在反汇编窗口才是这个作用,如果是在其他窗口按下esc,会关闭该窗口)
shift+f12:可以打开string窗口,一键找出所有的字符串,右击setup,还能对窗口的属性进行设置
ctrl+w:保存ida数据库
ctrl+鼠标滚轮:能够调节流程视图的大小
x:对着某个函数、变量按该快捷键,可以查看它的交叉引用
g:直接跳转到某个地址
n:更改变量的名称
y:更改变量的类型
/ :在反编译后伪代码的界面中写下注释
****:在反编译后伪代码的界面中隐藏/显示变量和函数的类型描述,有时候变量特别多的时候隐藏掉类型描述看起来会轻松很多
; :在反汇编后的界面中写下注释
ctrl+shift+w:拍摄IDA快照
u:undefine,取消定义函数、代码、数据的定义
结尾
文章有点长了,不利于阅读,后续分析看第二篇吧。