IDA with Appcall

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 会出手(

IDA with Appcall

idaapi.Appcall.printf("Hello from appcall")

Appcall 是一个对象,他下面包含了所有存在原型的函数
而且上一个例子中,我们调用的 printf 函数其实是存在在 exe 本身中的,但是如图,上面这一小行字就是他的函数原型,因此 ida 能够识别
IDA with Appcall
那么,如果没有 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 方法,就能得到这个对象解析后的

正文完
 0
评论(没有评论)