IDA

ida界面

记笔记记到控制流平台化突然想到,对于ida得各个界面,也得熟悉

汇编界面

汇编界面也是你一打开ida直接看到的,很多小白启程就在这里遇到第一个绊子,因为电脑运行程序是从

语言->汇编语言->机器码,所以这个是汇编代码,其中白色的模块,就是不同的代码段,其实还是很好理解的,每块之间用线连接

然后就可以F5

伪代码界面

这个就好理解了,这个就是伪代码,什么代码写的一般就是什么代码,不过一般都不是很好看丑丑的,看久了就习惯了

接下来是shift+F12

字符串

字符串寻找,就是你程序里会出现的字符串,比如说你一打开文件,就弹了个input,那就可以根据字符串查找到input,来找到主函数,这里搭配Ctrl+x食用

后面的暂时还没用到过

16进制

应该是机器码,突然想到这里是不是能改壳

ida代码修复

n是改名称,y是改类型

名称改写

比如这里我知道他是加密函数,但是sub_14A6太丑了就可以n然后输入你想要的名字(变量同理)

变量类型改写

如

这些灰色字体其实就是在提醒你这个类型是有问题的,一般来讲ida推荐的(灰色字体部分就是他的类型,当然也可以自己根据经验改),需要在你要改的变量前,按y,函数传参同理

函数类型改写

这个sub_14A6函数明显是不需要返回值的,但定义是int是没必要的,可以光标移动到

这里按”Y”,更改为void

回车后就会清爽很多

convert to array插件

​

这个是用于将变量类型转变成别的类型的,如我有这样的很长的数据

我想让他变成dword类型,且可观,先吧第一个类型变成dd(需要什么类型,就变成什么)

然后光标放在第一个上,打开插件

输入的第一行是你要改变多少个元素,第二个是一行几个,第三个是宽度,自己试试就会了

​

IDA 脚本

去nop脚本

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
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
# IDA Python 脚本
# 作用:在 start_ea..end_ea 范围内:
# 1) 将所有 "jmp rax" 指令用 NOP 覆盖(按原始字节长度)
# 2) 将所有目标为 end_ea 的跳转/调用指令也用 NOP 覆盖
# 3) 最后对整个区间 undefine(del_items)并在 start_ea 处 add_func
#
# 使用:修改 start_ea, end_ea 后运行
# 小心:会直接 patch 二进制,请事先备份 IDB / 文件

import idaapi
import idc
import ida_bytes
import idautils

# --------- 配置区域(请改为你自己的地址)---------
start_ea = 0x0000000180004990 # 起始地址(包含)
end_ea = 0x0000000180005F7F # 结束地址(包含)
PATCH_BYTES = True # True:实际写入 0x90;False:只做 undef/create_insn,不写字节
# ----------------------------------------------------

def patch_with_nops(ea, size):
"""用 0x90 覆盖 [ea, ea+size) 并尝试把每个字节创建为指令 (nop)"""
if size <= 0:
return
if PATCH_BYTES:
for i in range(size):
ida_bytes.patch_byte(ea + i, 0x90)
# 先删除原来的定义,然后把每个字节尝试创建为指令(这样 IDA 会显示为多个 nop)
idc.del_items(ea, size, idc.DELIT_SIMPLE)
for i in range(size):
# create_insn 返回 1 表示成功
idc.create_insn(ea + i)

def is_jump_to_target(ea, target):
"""判断指令 ea 是否是跳转/调用且目标等于 target。支持直接/相对立即数目标。"""
try:
# 对于常见分支/调用/跳转,operand 0 的值通常是目标地址(对相对立即数会被解析)
val = idc.get_operand_value(ea, 0)
if val == target:
return True
except Exception:
pass
# 作为补充,检查操作数文本中是否有十六进制目标(字符串匹配)
op0 = idc.print_operand(ea, 0)
if op0 is not None and hex(target).lower() in op0.lower():
return True
return False

def main():
if start_ea > end_ea:
print("错误:start_ea 大于 end_ea")
return

total_jmps = 0
total_target_jumps = 0
patched_ranges = []

# 遍历指定范围的所有 head(定义的 item:代码或数据)
for ea in idautils.Heads(start_ea, end_ea + 1):
mnem = idc.print_insn_mnem(ea)
# 1) 找到 jmp rax
if mnem.lower() == "jmp":
op0 = idc.print_operand(ea, 0) or ""
# 检查操作数是否包含 'rax' (覆盖大小写)
if "rax" in op0.lower():
size = idc.get_item_size(ea)
print("[NOP jmp rax] 0x%X size=%d" % (ea, size))
patch_with_nops(ea, size)
total_jmps += 1
patched_ranges.append((ea, size, "jmp rax"))
# 继续到下一个 head(注意:已把该区域覆写)
continue

# 2) 找到指令目标为 end_ea 的跳转/调用等
# 我们包括: jmp, je, jne, ja, jb, call 等(使用通用检测)
if mnem:
# 只处理可能带目标操作数的指令(跳转/调用/分支)
# 通用方法:尝试用 get_operand_value 获取目标,并与 end_ea 比较
try:
if is_jump_to_target(ea, end_ea):
size = idc.get_item_size(ea)
print("[NOP -> end] 0x%X (%s) size=%d" % (ea, mnem, size))
patch_with_nops(ea, size)
total_target_jumps += 1
patched_ranges.append((ea, size, "to_end"))
except Exception as e:
# 忽略读取错误
print("检查指令 0x%X 时出错: %s" % (ea, str(e)))

# 最后,对整个 start..end 区域 undefine(del_items)然后创建函数
length = end_ea - start_ea + 1
print("将整个区间 0x%X - 0x%X (%d bytes) 进行 undefine 并添加函数..." % (start_ea, end_ea, length))
idc.del_items(start_ea, length, idc.DELIT_SIMPLE)
# 尝试添加函数
if not idc.add_func(start_ea):
# 如果 add_func 失败,尝试 create_func (老版 API)
try:
idc.create_func(start_ea)
except Exception:
pass

print("完成:")
print(" jmp rax 被 NOP 的数量:%d" % total_jmps)
print(" 跳向 end_ea 被 NOP 的数量:%d" % total_target_jumps)
print(" 具体修改列表(ea, size, reason):")
for item in patched_ranges:
print(" 0x%X size=%d %s" % item)

if __name__ == "__main__":
main()

dump

还没找到插件,待会看看逆向王的语雀,先放一个脚本

1
2
3
4
5
import idaapi
data = idaapi.dbg_read_memory(start_address, data_length)
fp = open('d:\\dump', 'wb')
fp.write(data)
fp.close()
1
2
3
4
5
6
s = 0x00001B6B02B1FC0
l = 0x4c000
data=get_bytes(s, l)
fp = open('d:\\dump', 'wb')
fp.write(data)
fp.close()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
s = 0x0000000140009F83
e = 0x000000014000A35A
l = e - s

print('=================')
for i in range(l):
a = get_wide_byte(s + i)
b = get_wide_byte(s + i + 1)
#print('a = ', hex(a) , 'b = ' , hex(b))
if a == 0xE8 or a == 0xE9:
print('a real')
if b == 0x41:
print('b real')
patch_byte(s + i, 0x90)
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
import ida_bytes
import ida_ua
import ida_idaapi
import ida_auto
import idc

s = 0x0000000140009F83
e = 0x000000014000A35A

def is_jmp_reg_insn(ea):
insn = ida_ua.insn_t()
size = ida_ua.decode_insn(insn, ea)
if size <= 0:
return False, 0

mnem = idc.print_insn_mnem(ea)
if mnem != "jmp":
return False, 0

# op0 是寄存器
if insn.ops[0].type != ida_ua.o_reg:
return False, 0

return True, size

print("=================")

for cur in range(s, e):
a = ida_bytes.get_wide_byte(cur)
b = ida_bytes.get_wide_byte(cur + 1)

if a in (0xE8, 0xE9) and b == 0x41:
print("[+] suspicious junk at:", hex(cur))

prev = idc.prev_head(cur, s)
if prev == idc.BADADDR:
print(" [-] prev_head failed")
continue

ok, size = is_jmp_reg_insn(prev)
if not ok:
print(" [-] prev insn is not jmp reg:", hex(prev), idc.generate_disasm_line(prev, 0))
continue

# 确认上一条指令正好结束在 cur
if prev + size != cur:
print(" [-] prev insn does not end at cur:",
"prev =", hex(prev), "size =", size, "cur =", hex(cur))
continue

print(" [*] patch prev jmp-reg:", hex(prev), "size =", size,
"disasm =", idc.generate_disasm_line(prev, 0))

# NOP 掉前一条指令
ida_bytes.patch_bytes(prev, b"\x90" * size)

# 让 IDA 重新分析
ida_auto.auto_wait()
print("[+] done")

成品trace脚本

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
import idc, idautils, idaapi
import ida_dbg
class TraceHook(ida_dbg.DBG_Hooks):
def dbg_bpt(self, tid, ea):
print(f"[TRACE] Breakpoint hit at {hex(ea)}")

rax_val = idc.get_reg_value("rax")
rip_val = idc.get_reg_value("rip")

jmp_val = rax_val - rip_val - 2

print(hex(jmp_val))

patch_byte(rip_val - 3, 0xE9)
patch_dword(rip_val - 2, jmp_val)

idc.set_reg_value(rax_val, "rip")
return 0

trace_hook = TraceHook()
trace_hook.hook()

def is_indirect_jmp(ea):
mnem = idc.print_insn_mnem(ea)
if mnem != "jmp":
return False
op = idc.print_operand(ea, 0)
if "rax" in op:
return True
return False

def set_bpts_on_all_jmprax(start, end):
count = 0
for ea in idautils.Heads(start, end):
if is_indirect_jmp(ea):
if ida_dbg.add_bpt(ea):
print(f"Added breakpoint at {hex(ea)} -> op: {idc.print_operand(ea,0)}")
count += 1
print("Done. breakpoints added:", count)

set_bpts_on_all_jmprax(0x0000000180001000, 0x0000000180001251)
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
import ida_ua
import ida_hexrays
s = 0x0000000140009B0A
e = 0x0000000140009B6C
l = e - s

num = 0

def nop_area(start, end):
for i in range(start, end + 1):
patch_byte(i, 0x90)
return True

for i in range(l):
addr = s + i
next_addr = s + i + 1

baddr = get_wide_byte(addr)
caddr = ida_ua.print_insn_mnem(addr)
cnext_addr = ida_ua.print_insn_mnem(next_addr)

if baddr in (0xE8, 0xE9) and cnext_addr != None and cnext_addr.lower() == "pop":
num+=1
print('flower', num, 'at ', hex(addr), end = ' ')
#print('flower code is ', caddr)
for j_addr in range(addr, s, -1):
#print(hex(j_addr))
c = ida_ua.print_insn_mnem(j_addr)
if c != None and c.lower() == 'push':
print('push at', hex(j_addr))
break
#nop_area(j_addr, addr)
#ida_hexrays.decompile(addr)

idc

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
#include <idc.idc>

static main() {
auto start, end, ea, name, b1, b2;

// 1️⃣ 询问起始和结束地址
start = AskAddr(ScreenEA(), "请输入开始地址");
end = AskAddr(start, "请输入结束地址");

if (start == BADADDR || end == BADADDR || end <= start) {
Message("❌ 地址输入无效!\n");
return;
}

Message("📍 处理区间: %x - %x\n", start, end);

// 2️⃣ 将范围内定义为代码
for (ea = start; ea < end; ea = NextHead(ea, end)) {
MakeCode(ea);
}
Message("✅ 已尝试将该范围全部定义为代码。\n");

// 3️⃣ 给所有函数命名
ea = start;
while (ea < end) {
if (GetFunctionAttr(ea, FUNCATTR_START) == ea) {
name = form("func_%x", ea);
MakeName(ea, name);
MakeComm(ea, "自动命名的函数");
}
ea = NextFunction(ea);
if (ea == BADADDR)
break;
}
Message("🧩 已完成函数命名与注释。\n");

// 4️⃣ NOP 所有 jmp rax 指令 (opcode FF E0)
for (ea = start; ea < end - 1; ea++) {
b1 = Byte(ea);
b2 = Byte(ea + 1);
if (b1 == 0xFF && b2 == 0xE0) {
PatchByte(ea, 0x90);
PatchByte(ea + 1, 0x90);
MakeComm(ea, "已NOP掉 jmp rax");
}
}
Message("🧱 已将 jmp rax 指令全部 NOP。\n");

// 5️⃣ 输出总结
Message("🎯 IDC 脚本执行完成!范围: %x - %x\n", start, end);
}

x64dbg

xdbg界面

x64dbg好像是只能看汇编,不过确实很有用,一般是通过和ida配合使用,左下角那个窗口能看到,该程序在内存中的16进制文档,查找地址也可以通过ctrl+G实现,他上面的是光标所在行的一些信息,右键一个地址可以用转到内存窗口,来看到目标地址16进制的样子

常用工具

ScyllaHide插件

IDA7.5使用ScyllaHide反反调试-CSDN博客

反调试插件

这个插件适用于很多调试器如:x64dbg和ida

这个也是搁置了很多天啊,现在正是来看,在github上下载之后,解压点击.bat文件

1
2
3
D:\study\ctf\ScyllaHide\ScyllaHide-master>release.bat
XP toolchain build was requested, but VS2019 install dir could not be found.
Set USE_XP_TOOLCHAIN to something other than TRUE if you don't actually need it.

但是我有这样的报错,意思也很简单VS2019没找到,所以需要更改.bat文件,让他打开的是我装的VS2022

1
2
3
4
5
set VSWHERE=%PROGRAMFILES32%\Microsoft Visual Studio\Installer\vswhere.exe
if not exist "%VSWHERE%" (
echo VS2017/VS2019 installation directory does not exist, or the vswhere.exe tool is missing.
exit /b
)

在bat中找到上面这种将路径改成你的VS

VKD+windbg

新版windbg在微软官网下载即可

让我没有想到的是,这个VKD连接新版windbg的方式竟然是不选择路径

直接这样选择就可以了

CE

老实说我现在也不知道该把这篇内容写在哪了,用到ce+lua去编写简单脚本,后面写一个辅助,这到底算是项目呢还是CE呢还是lua呢

东一块西一块也很不好写,哎算了还是就分开吧,到时候项目直接贴源码思路就好,东西分开记还可以分开知识点的

基础用法不记了,很好用的工具

详细信息中的可能地址

找出是什么访问/改写了该地址 -> 指令 -> 详细信息

您要查找的地址可能是 :xxx

这个地址如果说这个指令是 mov eax, [rcx + 0x30]那么就是rcx的值

如果是mov eax, [rcx + rbx * 8],那么也是rcx的值

ce+lua

Cheat Engine教程:对步骤2教程编写一个lua脚本 - 吾爱破解 - 52pojie.cn

具体自己的实践在lua里

结构

Ctrl + Alt + D 打开,输入地址,选择定义新的结构,他会自动帮你猜测的

orca

分析msi的

https://bbs.kanxue.com/thread-258044-1.htm

https://blog.csdn.net/cssxn/article/details/111355932

安装

C:\Program Files\Microsoft SDKs\Windows\v6.0A\Bin\Orca.Msi,这个是安装包,SDK的话,怎么感觉是VS会自带的

嗯去查阅了一下,SDK在Visual Studio的C扩展安装里面(往下翻,倒数第二行好像是)下载之后再去看看有没有这个目录

简单说明

这个是看调用dll的

文件

二进制的部分

​