IDA基础安装使用详记

一,ida pro9 windows安装教程

下载地址:

下载地址: https://pan.baidu.com/s/1UPNzAsP9Ri1EFq9tVgvKrQ?pwd=b5c8 备用地址1:https://gofile.io/d/cdAsOw 备用地址2:https://pixeldrain.com/u/N3AffaTt 备用地址3:https://url31.ctfile.com/f/45624031-1524433990-2a077b?p=5170

压缩包解压结构:

参考教程:

https://bbs.kanxue.com/thread-285604.htm https://blog.csdn.net/sevendemage/article/details/136606750

1.安装python环境

运行目录安装包中的Python安装程序python-3.11.6-amd64.exe

一步一步根据自己的需求,点击完成安装即可。

注意安装过程中勾选环境变量PATH。

2.安装ida pro软件主体

运行目录安装包中的IDA Pro安装程序ida-pro_91_x64win.exe

一步一步根据自己的需求,点击完成安装即可

注意:IDA安装目录中不能包含中文。

3.激活

复制keygen_patch目录中的文件keygen.pyidapro.hexlic文件到IDA Pro主目录下。

修改keygen.py中的nameemail字段为自定义即可。start_dateend_dateissued_on字段可无需修改。

image-20250313161308372

保存修改并运行keygen.py脚本。

运行keygen.py后会生成 patch 后的文件ida.dll.patchedida32.dll.patched

我们需要先将原先的文件ida.dllida32.dll备份到其他目录或直接删除,然后将补丁文件ida.dll.patchedida32.dll.patched分别重新命名为ida.dllida32.dll

接着,我们需要把IDA Pro与Python3.11环境进行关联。

运行IDA Pro主目录中的idapyswitch.exe选择刚安装的Python3.11,输入对应的数字回车即可完成关联。

此时就可以运行IDA Pro主体程序,选择Help->License manager...,勾选刚才我们生成的许可证即可完成激活了。

再次点击Help->About program...即可查看激活状态。

4.插件安装

插件 功能
bindiff 文件对比
findcrypt-yara 识别常见加密算法
keypatch patch代码指令
WPeChatGPT 调用AI模型辅助分析代码
Hrtng 解密字符串,反混淆,括号高亮等。
classinformer 反编译C++时, 可以根据RTTI等信息综合恢复类Class的相关信息,例如继承信息,类名等。
deREferencing 调试时增强显示寄存器和堆栈数据
HexRaysCodeXplorer 自动识别结构体,显示C++虚函数,生成函数结构树等

(1)文件对比工具bindiff

https://github.com/google/bindiff

https://bbs.kanxue.com/thread-283804.htm

运行插件目录下的文件对比工具目录中的bindiff8.msi,完成bindiff8的安装。

拷贝目录插件->文件对比工具中的bindiff8_ida64.dllbinexport12_ida64.dll到目录C:\Users\xxx\AppData\Roaming\Hex-Rays\IDA Pro\plugins中。

如果之前安装过bindiff,该目录有残存的bindiff8_ida.dll、bindiff8_ida64.dll、binexport12_ida.dll、binexport12_ida64.dll,请先全部删除,再将上述两个文件拷贝进来。

(2)安装findcrypt-yara插件

https://github.com/polymorf/findcrypt-yara

拷贝插件->findcrypt-yara目录中的findcrypt3.pyfindcrypt3.rules到IDA插件目录中。

安装Python包依赖:

pip3 install yara-python -i https://pypi.tuna.tsinghua.edu.cn/simple

(3)安装keypatch插件

https://github.com/keystone-engine/keypatch

拷贝插件->keypatch目录中的keypatch.py到IDA插件目录中。

安装Python包依赖:

| `pip3 install keystone-engine -i https://pypi.tuna.tsinghua.edu.cn/simple

pip3 install six -i https://pypi.tuna.tsinghua.edu.cn/simple`

(4)安装WPeChatGPT插件

https://github.com/WPeace-HcH/WPeChatGPT

拷贝插件->WPeChatGPT目录中的WPeChatGPT.py以及文件夹Auto-WPeGPT_WPeace到IDA插件目录中。


安装Python包依赖:

| `pip3 install openai>=0.27.0 -i https://pypi.tuna.tsinghua.edu.cn/simple
pip3 install anytree -i https://pypi.tuna.tsinghua.edu.cn/simple

pip3 install httpx -i https://pypi.tuna.tsinghua.edu.cn/simple`

免费openai api key获取:

https://github.com/chatanywhere/GPT_API_free

获取到免费openai api key之后,修改文件WPeChatGPT.py中的model_api_keyproxy_address为chatanywhere官方的key及API访问地址即可。

修改模型为免费的gpt-3.5-turbo,或者充值后也可继续使用gpt-4

(5)安装Hrtng插件

https://github.com/KasperskyLab/hrtng

拷贝插件->Hrtng->windows目录中的hrtng.dll到IDA插件目录中。

(6)安装classinformer插件

https://github.com/herosi/classinformer

拷贝插件->ClassInformer目录中的ClassInformer64.dll到IDA插件目录中。

(7)安装deREferencing插件

https://github.com/danigargu/deREferencing

拷贝插件->WPeChatGPT目录中的dereferencing.py以及文件夹dereferencing到IDA插件目录中。

(8)安装HexRaysCodeXplorer插件

https://www.52pojie.cn/forum.php?mod=viewthread&tid=1999905&highlight=HexRaysCodeXplorer

拷贝插件->HexRaysCodeXplorer目录中的HexRaysCodeXplorer64.dll到IDA插件目录中。

至此,IDA Pro安装完成,插件安装完成,IDA Pro运行后终端无提示报错。

image-20250314131840906

二,静态分析基础

IDA 反汇编窗口

IDA 伪代码窗口

同理想知道该段代码的位置只需要光标确认后按Tab键进行切换

IDA 字符串表(快捷键:Shift + F12)

如示例进入rdata段,后面一次为内存地址,地址标识符名字,字符串

只收集IDA识别到的字符串

IDA 数据窗口

示例:

原始修改数据方法

在调试的时候会变成内存中的动态数据

IDA 交叉引用(快捷键:X 键)

Direction表示当前位置的上面还是下面。

Type引用类型

Address引用地址

双击跳转到引用位置

IDA 代码定位

看一个函数是被什么函数进行调用通过交叉引用查找

IDA的重命名

已分析函数进行重命名

快捷键总结

H键切换进制

不同类型的整数

  • 可通过快捷键 D 切换数据类型(byte/word/dword/qword)。
  • 使用 Shift+D 可自定义数据格式(如浮点、结构体、数组)。

多格式提取数据

示例:

ASCII形式展现通过U键进行展开

同理4字节就选择dword

数据与代码的转换

  • C:将数据转换为代码(强制反汇编)。
  • D:将代码转换为数据。
  • U:取消定义(undefine)。

示例:

jz,jnz一起表示强制跳转,那么下面指针一定不会被执行,可能就是数据,我们取消定义进行转化。

全部转化后让ida重新进行函数分析,需要先取消定义

将整个函数转化为数据后,在函数开头C键转换代码。然后再开头P键让IDA将此处识别为函数进行分析,最后Tab键进行处理。

  • 混合代码/数据区域:常见于壳或混淆代码,需手动切换。
  • 自动分析失败时:可手动指定代码起点,IDA 会尝试递归分析。
  • 使用 AnalyzeReanalyze program 重新分析整个模块。

IDA 函数调用图(Call Graph)

  • 查看函数调用关系:View → Open subviews → Function calls
  • 图形化调用图:右键函数 → Function call graph`。

示例:

向上查找

from从当前函数向下查找调用函数

  • 导出调用图:使用 gdlgraphviz 格式导出,供外部工具可视化。
  • 脚本批量提取调用关系

import idautils, idc, ida_funcs for func_ea in idautils.Functions(): print(f"Function: {idc.get_func_name(func_ea)}") for ref_ea in idautils.CodeRefsTo(func_ea, 0): print(f" Called by: {idc.get_func_name(ref_ea)}")


常数搜索(结构体偏移、OLLVM 真实块)

  • 搜索常数:Search → immediate value(快捷键 Alt+B)。
  • 可用于定位:
    • 结构体偏移(如 0x180x28
    • OLLVM 混淆中的真实块(通过常量跳转表)
  • 搜索结构体偏移
    • 假设结构体大小为 0x20,搜索 0x18 可能是访问最后一个成员。
  • OLLVM 真实块定位
    • 搜索 jmp eaxjmp [reg+offset] 前的常量,可能是真实块地址。

示例:

jdb调试app可以对系统调用设置断点。

立即数搜索

ollvm常数对应基本块→sub/cmp→对应跳转的基本块

混淆较多时可以直接通过value查找

将混乱基本块右键Layout graph还原


指令文本搜索 & 字节数据搜索

  • 文本搜索:Search → Text(快捷键 Alt+T)。

有些调用系统函数可以直接使用该方法查找

可以用来搜索特殊指令

  • 字节搜索:Search → Sequence of bytes(快捷键 Alt+B)。

  • 反调试指令搜索
    • 搜索 cpuidrdtscIsDebuggerPresentNtGlobalFlag
  • 特征码搜索
    • 搜索特定指令序列,如 64 A1 30 00 00 00(访问 TEB)。
  • YARA 规则集成
    • 使用 IDA 插件或外部工具(如 yara-python)匹配特征。

IDA 代码提取与编译使用

  • 提取伪代码:F5 反编译 → 右键 → Copy to clipboard
  • 提取汇编:Edit → Export → Dump assembly

  • 提取并重构代码
    • 使用 Hex-Rays SDKIDAPython 提取函数伪代码。
    • 使用 ClangMSVC 编译提取的代码,验证功能。
  • 自动化提取脚本

import ida_hexrays func = ida_funcs.get_func(here()) if func: cfunc = ida_hexrays.decompile(func) print(cfunc)

只需要引用ida中的这个头文件即可


IDA Patch(修改汇编并生效)

  • Edit → Patch program → Assemble(快捷键 Ctrl+Alt+K)。
  • keypatch修改
  • 修改后需使用 Edit → Patch program → Apply patches to input file 保存。

这里可以列举处所有修改的数据

  • 绕过反调试
    • jnz 改为 jmp,跳过调试检测。
  • NOP 掉指令
    • 使用 NOP 指令替换 call IsDebuggerPresent

将修改内容保存在文件中

  • 使用 Keypatch 插件
    • 支持汇编指令自动补全与 NOP 填充。

IDA 符号恢复(符号还原)

  • 导入 PDB:File → Load file → PDB file
  • 使用 FLIRT 签名识别库函数:View → Open subviews → Signatures
  • 自定义 FLIRT 签名
    • 使用 sigmake 工具从静态库生成 .sig 文件。
  • 恢复函数名
    • 使用 DiaphoraBinDiffLumina 进行函数匹配。
  • 使用符号服务器
    • 配置 Microsoft 符号服务器,自动下载 PDB。

LazyIDA提取数据

数据与代码转换(处理花指令)

  • 案例

    我们可以看到jz和jnz构成跳转指令到loc_405AF6,导致中间的指令不会运行。

    这里使用高亮功能显眼一些。我们到指定地方使用快捷键U将代码转换成数据。

    下面内容如法炮制一直更改到函数结束,选中区域,注意要到数据地址再向下一行进行填充

    Fill Range,整段就会被改写成 NOP,效果跟 IDA 原生菜单的 “Fill with NOPs” 完全一样,

    Assembly 栏里原来的 iz 1oc ... 全部删掉,只写nop,下方 “Fill byte” 框里填90

    同样如法炮制后让ida进行重新分析。

    回到函数头部重新转换为数据

    然后按C重新分析后我们使用F5返汇编尝试发现提示不是函数。

    我们在函数头部使用P创建函数就完成去花。

三,动态调试启动

什么是调试?

运行程序并观察程序运行过程中的控制流、寄存器、内存数据的变换,推测和验证程序的逻辑

IDA 支持哪些调试?
本地调试、远程调试(Linux/Android)、远程调试(gdb)、…

IDA 支持哪些调试操作?
查看/修改内存、查看/修改寄存器、反汇编/反编译调试内存、单步、追踪(Trace)、断点、调试脚
IDA 调试有哪些优势?
跨平台指令集操作统一
动态调试与静态分析操作统
支持伪代码级调试

1,windows本地调试

我们以验证看v8,v9的值来示例

链接启动调试

再次点击debuuger

我们这里启用新进程调试

我们发现会停到断点处

调试界面介绍

栈窗口

我们进去查看一下会发现内容中存放的内容

我们移动到代码结尾部分tab键查看调用位置。

数据窗口

同理想在Hex View中跳转也是同样的道理,先点击Hex View在点击小按钮即可‘

模块窗口

该窗口展示所有动态链接库

可以通过该窗口直接跳转到该动态链接库的函数下

想要添加窗口可已直接装在这里查询

寄存器窗口

寄存器窗口的小按钮可以实现点击后跳转。

同理,想要查看通用寄存器外的其它寄存器可以直接点击右键进行打开

同样双击寄存器可以修改值

简单功能

单步执行操作

步入F7,步过F8.步入到不感兴趣的函数直接Ctrl+F7返回原来的函数

F4直接下一步执行到我们F4标记的目标位置(常用于跳出调试循环)

将我们IP改到任意位置

调试命令行参数

示例

在此处配置调试命令行参数

2,远程调试

Windows远程调试


Linux远程调试

动态链接库调试

重定位

改为实际地址

调试时不能手动重定位断点可能会对不上

路由器固件模拟调试

3,Android Native调试

示例:

将对应的server push到手机端

赋予可执行文件权限

运行,并通过adb转发端口

adb forward tcp:23946 tcp:23946

调试时需要先设置好端口号等信息

选中我们要调试的进程(注意要在同一wifi下不然找不到的泪目ing)

电脑和手机端一个文件名,不用管直接save就行

进入后需要快速进行调试不然进程可能断掉或者被污染

进成自杀解决办法

临时关闭 JIT(需要 root,仅调试机)

JIT 编译时会主动触发 GC,关闭后 GC 次数明显减少:

adb root adb shell setprop dalvik.vm.usejit false adb shell stop adb shell start

调试完再改回 true 并重启 runtime 即可恢复。

终极黑科技——“暂停 GC 线程”(仅 gdb/IDA 下用)

仅当设备已 root 且你明确在调试阶段使用,用完立即恢复。

  1. 找到 GC 线程 tid(通常叫 GCDaemonHeapTaskDaemon

    adb shell ps -T -p <pid> | grep -i daemon

  2. 用 gdb 只停 GC 线程,不让它运行:

    (gdb) attach <pid> (gdb) info threads (gdb) thread apply <gc-tid> signal SIGSTOP

    这样 GC 永远进不了 STW 阶段,也就不会发 signal 35。调试结束后 thread apply <gc-tid> signal SIGCONT 放它继续即可。

四,动态调试技巧

1,断点

硬件断点

由硬件提供的断点机制,同时需要内核支持
硬件断点不会修改内存数据(隐蔽性高、不会破坏壳数据、自解密代码、代码校验等)
支持对数据/代码设置断点
一般有数量限制
◆应用场景:
加壳程序设置断点
自解密程序设置断点
自校验程序设置断点
日监控内存地址读写

……

硬件断点恢复数据

内存断点

对内存地址设置读写断点,命中修改该内存的指令
设置方法:在IDA-View窗口中按下G键,定位到目标内存,再按下F2键设置

默认情况下,内存断点,IDA 使用硬件断点实现,若要修改则在[edit Break Pointer中手日动修改
内存断点也可以设置IDAPython脚本

将这些勾选上即可

API断点

所谓 API断点就是指的直接对系统库提供的API接口设置断点,以此来达到定位关键代码的目的。
设置方法与普通断点一致。
跳转到API的方法如下:
方法1:IDA-View窗口>G键》输入导出符号名
方法2:[Debugger][Debugger Window]>[Module List]双击API所在的模块→双击对应的函数
找到API函数所在的内存之后,直接用F2设置断点即可。

2,调试内存

提取

修改

3,黑盒分析法

把程序当作黑盒,通过输入输出的关系来判断程序逻辑。

so黑盒调试示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
jstring __fastcall Java_com_pandaos_idacourse_MainActivity_enc(JNIEnv *a1, __int64 a2, void *a3)
{
const char *s; // x21
char *ptr; // x22
size_t n2; // x23
size_t v8; // x9
unsigned int v9; // w12
char *v10; // x13
unsigned int v11; // w14
size_t v12; // x17
char v13; // w3
char v14; // w0
size_t v15; // x10
char *v16; // x11
char v17; // w14
char *v18; // x24
jstring v19; // x23

if ( !fork() )
{
__android_log_print(3, "pandaos", "try DEBUG ME!");
init();
init();
init();
init();
init();
init();
init();
init();
init();
init();
init();
__android_log_print(3, "pandaos", "tell me special_key.");
exit(0);
}
s = (*a1)->GetStringUTFChars(a1, a3, 0); //a3 是 Java 层传进来的 jstring 参数,a3 是 Java 层传进来的 jstring 参数。
ptr = strdup(s); //strdup(s) 复制了一份这个字符串,赋值给 ptr。
n2 = strlen(s);
enc(ptr, n2);
if ( (int)n2 >= 1 )
{
if ( (unsigned int)n2 < 2uLL )
{
v8 = 0;
LABEL_8:
v15 = (unsigned int)n2 - v8;
v16 = &ptr[v8];
do
{
v17 = special_key[(unsigned int)v8 % 0xC8];
--v15;
LODWORD(v8) = v8 + 1;
*v16++ ^= v17;
}
while ( v15 );
goto LABEL_10;
}
v8 = (unsigned int)n2 - (n2 & 1);
v9 = 0;
v10 = ptr + 1;
v11 = 1;
v12 = v8;
do
{
v13 = *v10;
v14 = special_key[v11 % 0xC8];
v12 -= 2LL;
v11 += 2;
*(v10 - 1) ^= special_key[v9 % 0xC8];
*v10 = v13 ^ v14;
v10 += 2;
v9 += 2;
}
while ( v12 );
if ( (n2 & 1) != 0 )
goto LABEL_8;
}
LABEL_10:
v18 = (char *)operator new[](2 * n2);
base64_encode((unsigned __int8 *)ptr, v18, n2);
v19 = (*a1)->NewStringUTF(a1, v18); //ptr 被当作 UTF-8 字符串,封装成新的 jstring 返回。
(*a1)->ReleaseStringUTFChars(a1, a3, s);
free(ptr); //然后 ptr 被 free 掉。
operator delete[](v18);
return v19;
}

我们在进行这个代码的时候发现了ptr被输入和输出的逻辑,我们在这两个地方下断点。

那么中间的大量加密算法,比如中间 enc(ptr, n2);等,我们直接以enc为例进行分析

先设置断点调试运行到断点处

查看寄存器发现我们刚刚输入的字符串

将地址记录下来

000000749002DE50 DCB 0x31 ; 1

我们下面F8步过该函数到新断点处,我们回到刚刚的地址发现变成了密文

DCB 0x1D
[anon:libc_malloc]:000000749002DE41 DCB 0x77 ; w
[anon:libc_malloc]:000000749002DE42 DCB 0x9E
[anon:libc_malloc]:000000749002DE43 DCB 0xA4
[anon:libc_malloc]:000000749002DE44 DCB 0xAD
[anon:libc_malloc]:000000749002DE45 DCB 0x44 ; D
[anon:libc_malloc]:000000749002DE46 DCB 0x1E
[anon:libc_malloc]:000000749002DE47 DCB 0xAE
[anon:libc_malloc]:000000749002DE48 DCB 0x14
[anon:libc_malloc]:000000749002DE49 DCB 0x86

使用Set IP回到我们的输入位置,我们再尝试一下111111111

同理运行后我们回到相同位置变为了

我们再试一下12121212121

通过多次尝试不拿发现它应该是存在映射关系,所有1变为了1D,2变为了77

为了得到映射表我们将0~255输入得到映射内容进行查询即可。而我们注意到两个参数也位置有关,但照这样的思路简单映射下我们也就不用再管那500多行的enc是怎么实现的了。常用来完成研究魔改加密。

exe黑盒调试示例

打开程序我们会发现有明显不和谐的花指令

U取消定义后查看实际跳转哪里C重新编译,以此类推完成花指令处理

大致处理完之后我们的程序就很多了

我们尝试分析sub_401EF0,发现它在sub_403460内调用,有两个参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
__int64 __fastcall sub_403460(__int64 a1)
{
int v2; // eax
__int64 result; // rax
int v4; // edx

v2 = sub_401EF0(3i64);
*(_BYTE *)(a1 + 8) = 0;
*(_DWORD *)(a1 + 4) = v2;
result = 4i64;
while ( 1 )
{
v4 = result;
if ( *(_BYTE *)(a1 + result + 3) )
break;
if ( !--result )
{
v4 = 0;
break;
}
}
*(_DWORD *)a1 = v4;
return result;
}

而sub_403460程序执行到调用的地方需要满足传入字符串长度为64

我们在要分析的地方下断点

既然是黑盒分析我们观察一下输入输出函数都是一个int值

猜测应该是进行了一个数据变换

我们开始进行动态调试

我们随机生成功64个字符及逆行尝试

我们在断点后我们想要查看你返回值是多少。我们单步一下f8

我们发现单步后变为了000000000000FFFD

我们不断回到,通过修改寄存器的值得到不同结果。

我们观察发现下一项比前一项是2倍的关系,可以看出就是一个等比数列

4,Trace分析

示例:

进行配置

trace的三种模式

我们在最开始的位置下断点然后进行trace

我们有时候在脚本呢分析是时这种名字会影响分析

我们取消use nice name,这样我们就i得到了执行代码的trace

我们知道花指令的重要特点是不能干扰层序的正常执行流,而我们有了trace之后可以找到堆栈平衡点。就可以确定花指令区间,将区间代码去除掉从而找真实的代码。我们可以右键点击copy all及逆行文本提取

像这种肉眼可见啊,一行就是一条指令。第一列是:线程。python写脚本的时候就split一下第一列不要。它有一栏很重要,叫做这个result,result里面会有一些寄存器,这寄存器是什么呢?这些寄存器就是这一条,当前这条指令指明它会修改什么寄存器,修改之后的值。

push rax,那么push之后,这个RSP=000000000014FF20

这个站要平衡嘛,对吧?然后我们可以把这种所有的这种区间找出来啊,找出来,然后把花指令给给去除掉。

它这个花指令嵌套的比较多,然后当这个return之后呢,我们会发现。它有有一条指令和前面的不太一样,我们可以把这个这个认为是一条真实指令。

然后这条正式指令之后呢?它又开始了这种各种花指令嵌套。然后我们通过这种占平衡的思路,就可以找到这种真实指令。

我们也可以通过另外一种思路,就是指令序列匹配,比如说我们把这种push然后push fq。这样的一个一个整个的指令片段呢的特征记下来,然后我们用python的一个March。就也可以把他们给匹配出来,这样没匹配上的就是真实指令。

然后。用汇编器编译,然后再用ida进行分析,或者说直接看汇编啊,都是可以的。

5,Fork双进程调试法

然后这里一堆这个int函数呢,它会去修改这个special key的数据,然后修改完了之后。可能有些其他的用途。可能传递回主进程,然后进行一个post请求。所以说我们可以要想办法在这里提取它,魔改之后修改之后的这个special key,那special key的大小就是200个字节。

我们设置断点及逆行内容提取

g0db支持调试fork的,但是ida我们要想办法能附加到fork。

我们处理的方法就是把这里呢给它设置成一条死循环指令。然后它fork时候就会在这里死循环的等待,此时我们可以附加上去,对于所有没办法直接调试的,都可以用这种方法。

先在这个fork这里设置一个断点然后打开调试。

我们进行修改这里的地址,赋值ctrl+lt+k,再粘贴让它进入死循环。

此时呢,我们进行detach,再附加会发现有两个进程。

我们点击新进程前先附件调试断点

set IP,让它退出这个循环就可以接着调试。此时我们会发现,它其实全都变成了零。

有的时候两个进程可能会进行交互,就是要求我必须要有两个进程。那么这个时候我们就可以先detach第一个进程,然后第二个进程正在死循环的等待状态,然后我们在这个死循环这里设置一个断点附加上去。

6,Frida辅助IDA调试Linker/JNI_OnLoad

会有一些函数,这个函数会在这个so,这个动态链接库被加载的时候调用。直接附加的时候,这个函数已经被执行了,我们可以借助一个工具叫做Frida,它启动之后,会有一个暂停模式,就是说APk它启动了,但它并没有加载任何的库。

我们启动frida挂载该程序

通过该方法找到库函数

在挂载的时机启动进程

根据linux的调用原理我们找到该函数

这个里面的call_array方法进行调用

我们进入观察找到唯一调用的地方下断点

让程序保持运行状态释放frida,中间等待时间比较长到我们函数调用的地方

我们F7就进入到该函数中了

JNI_OnLoad也是同样的原理。

五,IDA Python脚本编程

1,寄存器操作

读取通用寄存器操作

调试器命中某个断点,就是具体的代码位置,并且停下来的时候,我们才能进行这方面的操作。

因为寄存器信息是一个程序的状态,它不是一个全局的状态。大部分内存就是全局的状态,只要程序在运行都可以去读写内存。局部变量等内存不具有全局性。

2,调试内存

用这些API接口来进行读取,ida它会直接从这个目标进程里面去读写它是实时的。

我们需要自己用这个pach debug byte来进行一个上层的封装。

本地内存接口

会在那个pass list,pass bytes那个中去找到我们的这些操作。

3,反汇编操作

GetDisasm(addr)#获取反汇编文本

idc.next head(ea)#获取下一条指令地址

ARM精简指令集,那它的指令长度是定长。

4,交叉引用分析

遍历得到ea的所有交叉引用

5,ollvm下批量设置断点

这样的ollvm变种混淆没办法解开的话我们可以进行批量代码设置断点

设置完后我们可以在断点窗口进行整合批量操作

6,杂项常用接口

idc.add_bpt(0x409437)添加断点
idaapi.get_imagebase()获取基地址

idc.create_insn(addr)#c, Make Code
ida_funcs.add_func(addr)#p,create function

ida_bytes.create_strlit(addr)#创建字符串,A 键效果

7,函数遍历

8,基本块

遍历

前驱

后继

9,指令遍历

里面填写函数起始地址

10,条件断点脚本编写

rax == 16949

可以利用该方法打印数据,作为hook来使用

11,Microcode

Microcode是hexrays 内部采用的介于机器代码与伪代码之间的一种中间表示语言(IR)。
目前,有许多编译器与反编译器都采用了中间表示语言,例如LLVMIR、IBinary的 NIL等。Ninjahexrays的microcode的IR,早在1999就有最版本。

Microcode 展示插件 https://github.com/gaasedelen/lucid

Microcode指令格式

Microcode 指令格式
opcode left, right, destination
一般来说有三个操作数,有一些指今可能缺少某个操作数,destination也不一定会被修改(Store指令)

Microcode寄存器

Microcode生成

最初非常冗余

最终输出

手动生成Microcode

Microcode数据结构

相关数据结构被定义在hexrays.hpp文件中

Microcode 相关的数据结构:mblarray_t这个结构用来存放函数的基本块信息。
基本块之间使用双向链表链接

基本块数组存放在natural数组

Microcode 相关的数据结构:mblockt这个结构用来描述基本块信息
基本块内的指令与指令之间使用双向链表链接

Microcode 相关的数据结构:minsnt用于描述指令信息的结构。
(注意微码指令支持指令嵌套。)

Microcode 相关的数据结构:mop_t
用于描述操作数信息的结构,指令minsnt有0~3个操作数,分别时1(left),r(right),(destination)操作数的类型用mop_t来表示。

实现svc0x900001与svc 0x9000F8指令反编译成一条call指令
install microcode filter 注册 microcode filter 实现拦截指令翻译
microcode_filter_t 是一种可以拦截 microcode 指令生成的机制,开发者需要继承4microcodefilter_t类并实现match与apply 两个函数。
ida 在生成某一条指令的 microcode 之前会调用所有已经注册的filter的match 函数,若match 函数返回 True,则调用对应的 apply 函数实现指令替换。
我们需要将svc指令替换成 call指令,ida已经为我们实现了替换类 udc_filter_t,这个类继承于 microcode_filter_t并实现了apply方法(即替换call指令),我们需要继承udc filtert并实现它的match 方法用于判断拦截的指令。

12,Hexrays Hooks

实现 IDA的回调类的不同事件的回调方法,获得不同事件

上面的例子是获取 Microcode 生成成功的回调,此时可以修改调试时,可以直接复制到 ida 底部运行,再次调试时先调用r.unhook()卸载其余回调可以参考文档中 Hexrays Hooks 的方法


IDA基础安装使用详记
https://cc-nx.github.io/2026/01/12/IDA基础安装使用详记/
作者
CC
发布于
2026年1月12日
许可协议