IDA Pro之IDA python介绍和功能(17)
IDA-IDC脚本编写语法
搞得我想买一本IDA Pro 权威指南来看看了……【有机会就整来看一看】
这个IDC用的比较少吧。下面的有些例子也不能正确的使用…
可以通过下面这个网址找到更多的IDC脚本
https://www.cnblogs.com/LyShark/p/13100048.html
file -> scriptcommand
file -> script file
由于这里汉化了,就比较容易了…
也许是这个用的少吧。笔记就不写了,反正也是copy也没有意义,就不浪费时间了。
IDA Python
IDC 能做到的 IDApython 也能做到,所以我们直接学IDApython 吧。
IDAPython 由三个独立的模块组成,一个是idc , 它是封装IDA的IDC函数的兼容性模块,第二个模块是idautils,这是IDA里的一个高级实用功能模块;第三个模块是idaapi,它允许访问更加底层的数据。
首先 , 我们知道我这个IDA7.7是基于这个python 3.8.10的版本..
要用pyhton 3 的语法 而不是 pyhton 2的语法
1 | 是 print ("hello") |
又来咯,估计还得学python…..
写一个题吧。从题目中体会。
题目来自CSAW CTF2017年的总决赛的一道逆向题目“Rabbithole”
题目和内容来自:
https://blog.csdn.net/ChuMeng1999/article/details/121228002
首先用die 看一下
发现是一个64位的,而且是在一个linux下的一个文件。用kali 运行一下。
“可以看到与一般的crackme差不多,就是要求我们输入,然后程序内部会有算法比对,如果不满足则报错”
现在用ida 64 位打开一下看一看。
可以看到这个一打开就是flag 。 用F5 看一下伪代码。
1 | int __cdecl main(int argc, const char **argv, const char **envp) |
看到这个主要的函数就是 check_value
这个check_value 有2个参数..s[v7] 和 v6[v7]
这个地方的v7 = 0LL 其实就是 0
1 | C/C++中各種不同型別的常數0,以不同的後綴表示: |
由于下面的 v7!=59 说明了 这个while 循环循环 while 59次。
然后这里的这个v6 = &roots; 说明这个roots 是一个地址,把这个地址点过去看一看。
因为,我们学过这个汇编语言中这个 offset 大概知道这个其实是一个偏移地址,也就是指针【差不多吧】
所以这个roots[] 数组 , 就是一个指针数组。。
然后去看看 check_value 这个函数的伪代码
1 | char __fastcall check_value(unsigned __int8 a1, __int64 a2) |
第一个参数就是s[v7] 第二个参数是 v6[v7]
也就是说 第一个参数:s[v11]是用户输入input,第二个参数: (_int64)v10[v11])是roots。
至于为什么这个s[v11]是用户输入input,是因为fgets(s, 127, _bss_start)【应该是的吧。我是这样理解的】
这个fget()函数和get函数差不多。更牛皮一点罢了。【参数更多】
1 | if ( *(_BYTE *)(a2 + 8) > a1 || *(_BYTE *)(a2 + 9) <= a1 ) |
大概看一下这个代码。估计也就是算法,把不同情况下的东西进行不同的操作。
首先是roots指针数组的起始位置,因为node的地址都是在其上进行偏移计算的。
可以看到其值为28f900:
然后需要写两个函数,一个用于遍历,一个用于校验。
前面已经分析过遍历的次数是59次,10进制的59就是16进制的0x3b。
使用ida_bytes.get_qword来取得node的地址:
接下来就是在ascii字符中遍历了,我们知道ascii码中32-126是字符,即需要在0x20到0x7f的范围内遍历。针对每一个可能的字符都是用校验函数来校验,如果返回为真,则将其添加进flag,然后break循环,然后在roots数组中偏移8取下一个node,再针对下一个位置的字符再次遍历。
所以校验的函数应该这么写:
1 | for i in range(0,0x3b) : |
这里的traverse_find 函数就是我们等会儿要写的进行校验的函数。
Traverse_find的逻辑其实就是check_value伪码的逻辑,只要注意两点:
1.逻辑,如下图,C伪码中使用的是||逻辑表达式,比如A||B,意思是满足A,B中的任一个就为真。
简化的表示:
下图中的A就是*(_BYTE )(a2 + 8),B就是(_BYTE )(a2 + 9),C就是a2 =(_QWORD )(a2 + 24),D就是a2 =(_QWORD *)(a2 + 16)。
伪码的逻辑是满足A>a1或B<=a1(a1就是input),则执行C,否则执行D;
我在python脚本里使用的是and,所以判断的语句用的是:
A <= c and B > c(这里c就是input)。
如果满足条件,则执行D,否则执行C;
可以看到python和C伪码的逻辑是一样的,不过用的逻辑运算符不一样而已,这里一定要注意,不要混淆了。
2.进制转换:
比如下图中第6行,第8行的两个分支:
他们在原基础上继续偏移24,16;转换成16进制分别是0x18,0x10。
最后写出来的IDA python 脚本
1 | from idaapi import * |
这里,我用的IDA用的是这个python3.8.10的版本的。所以需要用的是python3 的语法,也就是这个print 函数的写法不一样。
如果是python 2 就直接 print flag
这个题,是一个关于树的题。我自己来写一下呢?
最后我知道了几个WP
https://anee.me/rabbithole-csaw-ctf-2017-finals-f7d70f3726f3