Appcall 是什么
ida 中有很多函数事实上是存在函数原型的(一般来自 pdb 或自己定义),也就是说,ida 知道这个函数的参数类型,返回值等等。因此,ida 也提供了调用这些函数的能力,无论他是在内存的 dll 中,或是在可执行文件中。
但首先,因为要调用这些函数,程序必须被运行在调试模式。当然,暂不暂停程序是无所谓的,ida 作为调试器可以在暂停程序的时候执行里面的函数。
这个 ida 的特性被提到的比较少, 但是事实上它是很强大的。由于使用了 ida API,所以他可以和条件断点配合起来使用,可以说是非常灵活的工具
ida appcall in IDC
ida 默认的 api 都由 idc 提供,而且对于将这些函数默认认为是 c 语言函数的 ida 来说,使用 idc 去 call 他们是非常好的
但是我相信大家对于 idc 都没有那么熟悉,因此下面略讲一下
当然,函数需要有函数原型,不然需要 add local type
使用 enum 也同理
直接 console 输入结构体名,可以打印详细信息
apply_type 函数可以为函数定义原型
idc 脚本
static main(){dbg_appcall(LocByName("name"),args);
}
appcall in idapython
事实上 appcall 被封装在 ida_idd 里面。但是无所谓,idaapi 会出手(
idaapi.Appcall.printf("Hello from appcall")
Appcall 是一个对象,他下面包含了所有存在原型的函数
而且上一个例子中,我们调用的 printf 函数其实是存在在 exe 本身中的,但是如图,上面这一小行字就是他的函数原型,因此 ida 能够识别
那么,如果没有 pdb,我们该怎么办呢
添加函数原型
Appcall.proto(func_name、func_ea、prototype_string)
# Create a typed object (no address is associated yet)
virtualalloc = Appcall.typedobj("int __stdcall VirtualAlloc(int lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect);")
# Later we have an address, so we pass it:
virtualalloc.ea = LocByName("kernel32_VirtualAlloc")
# Now we can Appcall:
ptr = virtualalloc(0, Appcall.Consts.MEM_COMMIT, 0x1000, Appcall.Consts.PAGE_EXECUTE_READWRITE)
可以看一个例子
MyFunc = Appcall.proto("kernel32_loadLibraryA","HMODULE MyFunc(const char * name);")
MyFunc("user32.dll")
不过这里注意点,传递 Unicode 需要这个
Appcall.unicode(" 你好 ")
这样子就能加载一个自定义的 dll,是一个很简单的 appcall 的用法
也就是说,名字不重要,重要的是在前面让 ida 知道你是要调用的函数在哪里,那么 proto 的返回值就是一个可以调用的函数
以结构体作为参数的函数
结构体一直都是逆向里面一个比较难搞的东西。当你想要调用一个以结构体作为参数的函数时,就需要创建一个 python 字典来模拟你的结构体,或是直接使用 Appcall.obj() 来创建一个对象
obj1 = {"id":8,"name":"dr3"}
obj2 = Appcall.obj(id=8,name="dr3")
MyFunc2(obj1)
得到一块内存
如果这个函数需要传入一块内存呢?
当然,可以选择手动 malloc 一下,但是 ida 提供了
Appcall.byref("\x00"*1024)
这样就能创建一块有 1024 个 0 字节的内存
当然,不想初始化也可以
Appcall.buffer(size=1024)
typedobj
def typedobj(typedecl_or_tinfo, ea=None)
Returns an appcall object for a type (can be given as tinfo_t object or as a string declaration) One can then use retrieve() member method
ea: Optional parameter that later can be used to retrieve the type
return: Appcall object or raises ValueError exception
例如,知道一个对象在内存中的位置,先得到 typedobj 对象,然后调用其 retrive 方法,就能得到这个对象解析后的