做pyd的题做吐了,想骂人

动态看,一坨

静态看,更是依托

所以,我要写一个通用的hook脚本,hhhhhhh

Hook编写

在Linux下通过pip install Cython安装。安装完毕后执行cython --version,如果输出了版本号即安装成功。

安装完成后,我们创建一个hook_test项目,需要创建hook_test.pyxsetup.py两个文件。

1
2
3
4
5
6
7
8
9
10
# setup.py
from distutils.core import setup
from Cython.Build import cythonize

# setup() 函数是核心,它定义了如何构建你的模块
setup(
# 'name' 字段是这个模块的名称,可以自定义
name='hook_test',
ext_modules=cythonize("hook_test.pyx")
)
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
# hook_test.pyx
def process_data(a, b, c, d, e):
num1 = a + b
print("PyNumber_Add:", num1)
num2 = a - b
print("PyNumber_Subtract:", num2)
num3 = a * b
print("PyNumber_Multiply:", num3)
num4 = a & b
print("PyNumber_And:", num4)
num5 = a | b
print("PyNumber_Or:", num5)
num6 = a ^ b
print("PyNumber_Xor:", num6)
num7 = a << 2
print("PyNumber_Lshift:", num7)
num8 = b >> 1
print("PyNumber_Rshift:", num8)
b >>= 1
print("PyNumber_InPlaceRshift:", b)
num10 = a ** 2
print("PyNumber_Power:", num10)
num11 = a % 100
print("PyNumber_Remainder:", num11)
num13 = e[0]
print("PyNumber_Index:", num13)
c += a
print("PyNumber_InPlaceAdd:", c)
return a == b

然后使用下述命令进行编译:

python setup.py build_ext --inplace

获得pyd文件

随后:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# challenge.py
import hook_test
import os
import sys
print(sys.executable)
print(os.getpid())

if hasattr(sys, "set_int_max_str_digits"):
sys.set_int_max_str_digits(0)
# 准备输入数据
a = 1234345
b = 67890
c = 13579
d = 24680
e = [42,53]
# 调用 Cython 函数
input()
hook_test.process_data(a, b, c, d, e)
print("调用成功")

首先运行challenge.py,然后运行hook代码即可:frida -p 14240 -l hook_05.js

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
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
'use strict';
/**
* ======================================================
* Frida hook script for Python3 numeric & compare ops
* - Hooks PyNumber_* (加减乘除、位运算、取余、移位、模幂)
* - Hooks PyObject_RichCompareBool / PyObject_RichCompare (比较)
* - Hooks PyLong_FromString / PyLong_FromUnicodeObject
* - Fixed type error: use int64/uint64 instead of longlong
* - Added fixed-width HEX output (e.g. 0x12345678)
* ======================================================
*/

const logFilePath = "./log.txt";
const logFile = new File(logFilePath, "w");

function logLine(s) {
logFile.write(s + "\n");
logFile.flush();
console.log(s);
}

// ---------------------------------------------------------------------

function findPythonModule() {
const mods = Process.enumerateModulesSync();
for (const m of mods) {
const n = m.name.toLowerCase();
if (n.startsWith('python3') && n.endsWith('.dll')) return m;
if (n.startsWith('python') && n.endsWith('.dll')) return m;
}
throw new Error('python3*.dll not found. Use: frida -f python.exe -l hook_number_compare.js');
}

const pymod = findPythonModule();
logLine('[*] using python module: ' + pymod.name + ' ' + pymod.base);

// safe wrapper to resolve exports and print status
function exp(name) {
try {
const addr = Module.getExportByName(pymod.name, name);
logLine(`[+] export ${name} => ${addr}`);
return addr;
} catch (e) {
logLine(`[-] export ${name} not found`);
return null;
}
}

// ---------------------------------------------------------------------

// list of symbols
const symbols = {
PyUnicode_AsUTF8: exp('PyUnicode_AsUTF8'),
PyObject_Repr: exp('PyObject_Repr'),
PyObject_Str: exp('PyObject_Str'),
PyLong_Check: exp('PyLong_Check'),
PyLong_AsLongLong: exp('PyLong_AsLongLong'),
PyLong_AsUnsignedLongLongMask: exp('PyLong_AsUnsignedLongLongMask'),
PyLong_FromString: exp('PyLong_FromString'),
PyLong_FromUnicodeObject: exp('PyLong_FromUnicodeObject'),
PyNumber_Add: exp('PyNumber_Add'),
PyNumber_InPlaceAdd: exp('PyNumber_InPlaceAdd'),
PyNumber_Subtract: exp('PyNumber_Subtract'),
PyNumber_Multiply: exp('PyNumber_Multiply'),
PyNumber_And: exp('PyNumber_And'),
PyNumber_Or: exp('PyNumber_Or'),
PyNumber_Xor: exp('PyNumber_Xor'),
PyNumber_Lshift: exp('PyNumber_Lshift'),
PyNumber_Rshift: exp('PyNumber_Rshift'),
PyNumber_InPlaceRshift: exp('PyNumber_InPlaceRshift'),
PyNumber_Power: exp('PyNumber_Power'),
PyNumber_Remainder: exp('PyNumber_Remainder'),
PyNumber_Index: exp('PyNumber_Index'),
PyObject_RichCompare: exp('PyObject_RichCompare'),
PyObject_RichCompareBool: exp('PyObject_RichCompareBool')
};

function tryCreateNativeFunction(addr, retType, argTypes, friendlyName) {
if (!addr) return null;
try {
const nf = new NativeFunction(addr, retType, argTypes);
logLine(`[+] NativeFunction created for ${friendlyName}`);
return nf;
} catch (e) {
logLine(`[-] Failed creating NativeFunction for ${friendlyName}: ${e.message}`);
return null;
}
}

const PyUnicode_AsUTF8 = tryCreateNativeFunction(symbols.PyUnicode_AsUTF8, 'pointer', ['pointer'], 'PyUnicode_AsUTF8');
const PyObject_Repr = tryCreateNativeFunction(symbols.PyObject_Repr, 'pointer', ['pointer'], 'PyObject_Repr');
const PyObject_Str = tryCreateNativeFunction(symbols.PyObject_Str, 'pointer', ['pointer'], 'PyObject_Str');
const PyLong_Check = tryCreateNativeFunction(symbols.PyLong_Check, 'int', ['pointer'], 'PyLong_Check');
const PyLong_AsLongLong = tryCreateNativeFunction(symbols.PyLong_AsLongLong, 'int64', ['pointer'], 'PyLong_AsLongLong');
const PyLong_AsUnsignedLongLongMask = tryCreateNativeFunction(symbols.PyLong_AsUnsignedLongLongMask, 'uint64', ['pointer'], 'PyLong_AsUnsignedLongLongMask');

// ---------------------------------------------------------------------

function toHexFixed(num, width = 8) {
try {
let big;
if (typeof num === 'bigint') big = num;
else if (typeof num === 'number') big = BigInt(num >>> 0);
else if (typeof num === 'string') {
if (/^0x[0-9a-fA-F]+$/.test(num)) big = BigInt(num);
else if (/^-?\d+$/.test(num)) {
big = BigInt(num);
if (big < 0n) {
const bits = BigInt(width * 4);
big = (big & ((1n << bits) - 1n));
}
} else return num;
} else return `<hex error: ${typeof num}>`;
let hex = big.toString(16);
if (hex.length < width) hex = hex.padStart(width, '0');
return '0x' + hex;
} catch (e) {
return `<hex error: ${e.message}>`;
}
}

function isDecimalString(s) {
return typeof s === 'string' && /^-?\d+$/.test(s);
}
function isHexString(s) {
return typeof s === 'string' && /^0x[0-9a-fA-F]+$/.test(s);
}

function formatForLogging(s, width = 8) {
if (s === undefined || s === null) return s;
if (isHexString(s)) return s;
if (isDecimalString(s)) return toHexFixed(s, width);
const m = /(-?\d+)$/.exec(String(s).trim());
if (m) return toHexFixed(m[1], width);
return s;
}

function safeUtf8FromPyStr(pyStrPtr) {
if (!pyStrPtr || pyStrPtr.isNull()) return '<utf8 NULL>';
try {
if (!PyUnicode_AsUTF8) return '<no PyUnicode_AsUTF8>';
const cstr = PyUnicode_AsUTF8(pyStrPtr);
if (cstr.isNull()) return '<utf8 NULL>';
return Memory.readUtf8String(cstr);
} catch {
return '<utf8 read error>';
}
}

function objToStr(pyObjPtr) {
if (!pyObjPtr || pyObjPtr.isNull()) return '<NULL>';
try {
if (PyLong_Check) {
const isLong = PyLong_Check(pyObjPtr);
if (isLong === 1) {
if (PyLong_AsUnsignedLongLongMask) {
const u = PyLong_AsUnsignedLongLongMask(pyObjPtr);
return toHexFixed(u);
}
if (PyLong_AsLongLong) {
const v = PyLong_AsLongLong(pyObjPtr);
return toHexFixed(v);
}
}
}
if (PyObject_Str) {
const sObj = PyObject_Str(pyObjPtr);
if (sObj && !sObj.isNull()) return safeUtf8FromPyStr(sObj);
}
if (PyObject_Repr) {
const r = PyObject_Repr(pyObjPtr);
if (r && !r.isNull()) return safeUtf8FromPyStr(r);
}
return '<unrepresentable>';
} catch (e) {
return `<repr error: ${e.message}>`;
}
}

// ---------------------------------------------------------------------

// Hook PyLong_FromUnicodeObject / PyLong_FromString
if (symbols.PyLong_FromUnicodeObject) {
Interceptor.attach(symbols.PyLong_FromUnicodeObject, {
onEnter(args) {
this.sRaw = objToStr(args[0]);
this.base = args[1].toInt32();
},
onLeave(retval) {
const got = objToStr(retval);
logLine(`[PyLong_FromUnicodeObject] int(s, base=${this.base}) s=${this.sRaw} -> ${formatForLogging(got)}`);
}
});
}

if (symbols.PyLong_FromString) {
Interceptor.attach(symbols.PyLong_FromString, {
onEnter(args) {
try { this.s = Memory.readUtf8String(args[0]); } catch (e) { this.s = '<read error>'; }
this.base = args[2].toInt32();
},
onLeave(retval) {
const got = objToStr(retval);
logLine(`[PyLong_FromString] int(s, base=${this.base}) s=${this.s} -> ${formatForLogging(got)}`);
}
});
}

function symbolFor(name) {
const map = {
PyNumber_Add: '+',
PyNumber_InPlaceAdd: '+=',
PyNumber_Subtract: '-',
PyNumber_Multiply: '*',
PyNumber_And: '&',
PyNumber_Or: '|',
PyNumber_Xor: '^',
PyNumber_Lshift: '<<',
PyNumber_Rshift: '>>',
PyNumber_InPlaceRshift: '>>=',
PyNumber_Power: '**',
PyNumber_Remainder: '%',
PyNumber_Index: 'index'
};
return map[name] || '?';
}

// ---------------------------------------------------------------------
//
// function hookPyNumber(name, ptr) {
// if (!ptr) return;
// Interceptor.attach(ptr, {
// onEnter(args) {
// this.aPtr = args[0];
// this.bPtr = args[1];
// this.aRaw = objToStr(this.aPtr);
// this.bRaw = objToStr(this.bPtr);
// this.a = formatForLogging(this.aRaw, 8);
// this.b = formatForLogging(this.bRaw, 8);
// try {
// this.cPtr = args[2];
// if (this.cPtr && !this.cPtr.isNull()) {
// this.cRaw = objToStr(this.cPtr);
// this.c = formatForLogging(this.cRaw, 8);
// } else {
// this.cPtr = null;
// }
// } catch (e) { this.cPtr = null; }
// },
// onLeave(retval) {
// if (name === 'PyNumber_Power') {
// if (this.cPtr) {
// logLine(`[${name}] pow(${this.a}, ${this.b}, ${this.c}) = ${formatForLogging(objToStr(retval), 8)}`);
// } else {
// logLine(`[${name}] ${this.a} ** ${this.b} = <suppressed>`);
// }
// return;
// }
// logLine(`[${name}] ${this.a} ${symbolFor(name)} ${this.b} = ${formatForLogging(objToStr(retval), 8)}`);
// }
// });
// }

function hookPyNumber(name, ptr) {
if (!ptr) return;
Interceptor.attach(ptr, {
onEnter(args) {
// onEnter 的逻辑保持不变,依然是捕获原始指针和字符串
this.aPtr = args[0];
this.bPtr = args[1];
this.aRaw = objToStr(this.aPtr);
this.bRaw = objToStr(this.bPtr);
this.a = formatForLogging(this.aRaw, 8);
this.b = formatForLogging(this.bRaw, 8);

try {
this.cPtr = args[2];
if (this.cPtr && !this.cPtr.isNull()) {
this.cRaw = objToStr(this.cPtr);
this.c = formatForLogging(this.cRaw, 8);
} else {
this.cPtr = null;
this.cRaw = null;
this.c = null;
}
} catch (e) {
this.cPtr = null;
this.cRaw = null;
this.c = null;
}
},
onLeave(retval) {
// --- 主要修改部分在这里 ---

// 1. 统一检查并准备用于日志的字符串
// 检查第一个操作数 a
let aStr = this.aRaw.length > 32 ? "num" : this.a;
// 检查第二个操作数 b
let bStr = this.bRaw.length > 32 ? "num" : this.b;
// 检查返回值 (c)
const outRaw = objToStr(retval);
let outFmt = outRaw.length > 32 ? "num" : formatForLogging(outRaw, 8);


// 2. 根据不同的函数名,使用准备好的字符串来格式化日志
if (name === 'PyNumber_Power') {
// 对于 pow(a, b, mod),第三个参数也需要检查
let modStr = this.c ? (this.cRaw.length > 32 ? "num" : this.c) : "None";
logLine(`[${name}] pow(${aStr}, ${bStr}, ${modStr}) = ${outFmt}`);
return;
}

// 对于 PyNumber_Remainder 和其他所有二元运算
logLine(`[${name}] ${aStr} ${symbolFor(name)} ${bStr} = ${outFmt}`);
}
});
}
// ---------------------------------------------------------------------

[
'PyNumber_Add',
'PyNumber_InPlaceAdd',
'PyNumber_Subtract',
'PyNumber_Multiply',
'PyNumber_And',
'PyNumber_Or',
'PyNumber_Xor',
'PyNumber_Lshift',
'PyNumber_Rshift',
'PyNumber_InPlaceRshift',
'PyNumber_Remainder',
'PyNumber_Index',
'PyNumber_Power'
].forEach(n => hookPyNumber(n, symbols[n]));

// 比较操作
const cmpOps = ['<', '<=', '==', '!=', '>', '>='];

if (symbols.PyObject_RichCompareBool) {
Interceptor.attach(symbols.PyObject_RichCompareBool, {
onEnter(args) {
this.ptrA = args[0];
this.ptrB = args[1];
this.op = args[2].toInt32();
this.aRaw = objToStr(this.ptrA);
this.bRaw = objToStr(this.ptrB);
this.a = formatForLogging(this.aRaw, 8);
this.b = formatForLogging(this.bRaw, 8);
},
onLeave(retval) {
const opStr = cmpOps[this.op] || `op(${this.op})`;
if (this.ptrA.equals(this.ptrB)) return;
if (this.aRaw === this.bRaw && this.op === 2) return;
logLine(`[CompareBool] ${this.a} ${opStr} ${this.b} -> ${retval.toInt32()}`);
}
});
}

if (symbols.PyObject_RichCompare) {
Interceptor.attach(symbols.PyObject_RichCompare, {
onEnter(args) {
this.aRaw = objToStr(args[0]);
this.bRaw = objToStr(args[1]);
this.op = args[2].toInt32();
this.a = formatForLogging(this.aRaw, 8);
this.b = formatForLogging(this.bRaw, 8);
},
onLeave(retval) {
logLine(`[CompareObj] ${this.a} ${cmpOps[this.op]} ${this.b} -> ${objToStr(retval)}`);
}
});
}

logLine(`\n✅ Hooks installed on ${pymod.name}`);
logLine(`🧮 PyNumber_* operations + Compare ops are now being traced in HEX...\n`);

但是有个问题,hook不是万能的,hook不全所有的函数,比如对于Lshift、Rshift等逻辑操作来说,是hook不到的,因为有可能他就不走 Py提供的库函数,直接在pyd中自己实现了

总结了一下,我写的hook_test

1
2
3
4
5
6
7
8
9
10
11
12
13
14
PyNumber_Add: 1302235
PyNumber_Subtract: 1166455
PyNumber_Multiply: 83799682050
PyNumber_And: 288
PyNumber_Or: 1301947
PyNumber_Xor: 1301659
PyNumber_Lshift: 4937380
PyNumber_Rshift: 33945
PyNumber_InPlaceRshift: 33945
PyNumber_Power: 1523607579025
PyNumber_Remainder: 45
PyNumber_Index: 42
PyNumber_InPlaceAdd: 1247924
CompareObj

一共14种,但是我只hook到了9种:

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
[*] using python module: python312.dll 0x7ffcf6920000
[+] export PyUnicode_AsUTF8 => 0x7ffcf6ac3c58
[+] export PyObject_Repr => 0x7ffcf6998af8
[+] export PyObject_Str => 0x7ffcf6998968
[-] export PyLong_Check not found
[+] export PyLong_AsLongLong => 0x7ffcf69e17d4
[+] export PyLong_AsUnsignedLongLongMask => 0x7ffcf6a9b880
[+] export PyLong_FromString => 0x7ffcf69e3d60
[+] export PyLong_FromUnicodeObject => 0x7ffcf69e35a0
[+] export PyNumber_Add => 0x7ffcf699fd9c
[+] export PyNumber_InPlaceAdd => 0x7ffcf6a76230
[+] export PyNumber_Subtract => 0x7ffcf6951bc8
[+] export PyNumber_Multiply => 0x7ffcf69e6808
[+] export PyNumber_And => 0x7ffcf6982ba8
[+] export PyNumber_Or => 0x7ffcf6951b10
[+] export PyNumber_Xor => 0x7ffcf6951ab4
[+] export PyNumber_Lshift => 0x7ffcf6a6f47c
[+] export PyNumber_Rshift => 0x7ffcf6982980
[+] export PyNumber_InPlaceRshift => 0x7ffcf6aadfa0
[+] export PyNumber_Power => 0x7ffcf6b6d228
[+] export PyNumber_Remainder => 0x7ffcf6951a58
[+] export PyNumber_Index => 0x7ffcf69ede34
[+] export PyObject_RichCompare => 0x7ffcf69e7610
[+] export PyObject_RichCompareBool => 0x7ffcf69913d8
[+] NativeFunction created for PyUnicode_AsUTF8
[+] NativeFunction created for PyObject_Repr
[+] NativeFunction created for PyObject_Str
[+] NativeFunction created for PyLong_AsLongLong
[+] NativeFunction created for PyLong_AsUnsignedLongLongMask

✅ Hooks installed on python312.dll
🧮 PyNumber_* operations + Compare ops are now being traced in HEX...

[PyNumber_Add] 0x0012d5a9 + 0x00010932 = 0x0013dedb
[PyNumber_Subtract] 0x0012d5a9 - 0x00010932 = 0x0011cc77
[PyNumber_Multiply] 0x0012d5a9 * 0x00010932 = 0x1382d9ac02
[PyNumber_And] 0x0012d5a9 & 0x00010932 = 0x00000120
[PyNumber_Or] 0x0012d5a9 | 0x00010932 = 0x0013ddbb
[PyNumber_Xor] 0x0012d5a9 ^ 0x00010932 = 0x0013dc9b
[PyNumber_Power] pow(0x0012d5a9, 0x00000002, None) = 0x162be16a991
[PyNumber_InPlaceAdd] 0x0000350b += 0x0012d5a9 = 0x00130ab4
[CompareObj] 0x0012d5a9 == 0x00008499 -> False

可以确定的是,移位或者取值操作是hook不到的

1
2
3
4
5
PyNumber_Lshift
PyNumber_Rshift
PyNumber_InPlaceRshift
PyNumber_Index
PyNumber_InPlaceAdd

但是,PyNumber_Remainder可能可以

依旧国赛初赛rand0m: ((int(n,16)^2654435769)>>11)**65537%4294967293

这个运算里面的%就可以hook到……….. 我写的num11 = a % 100不行,woc,凭啥啊………..

实战(我要一把梭…)

2024ciscn长城杯_rand0m

不用ida哈,直接跑hook

input:12345678876543211234567887654321

log.txt

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
[PyLong_FromString] int(s, base=16) s=12345678 -> 0x12345678
[PyLong_FromUnicodeObject] int(s, base=16) s=12345678 -> 0x12345678
[PyNumber_Xor] 0x12345678 ^ 0x9e3779b9 = 0x8c032fc1
[PyNumber_And] 0x123456780 & 0xfa3affff = 0x22006780
[PyNumber_Add] 0x22006780 + 0x00000001 = 0x22006781
[PyNumber_Power] pow(0x00118065, 0x00010001, None) = num
[PyNumber_Remainder] num % 0xfffffffd = 0x8c219e43
[CompareObj] 0x22006781 == 0x12287f38 -> False

[PyLong_FromString] int(s, base=16) s=87654321 -> 0x87654321
[PyLong_FromUnicodeObject] int(s, base=16) s=87654321 -> 0x87654321
[PyNumber_Xor] 0x87654321 ^ 0x9e3779b9 = 0x19523a98
[PyNumber_And] 0x876543210 & 0xfa3affff = 0x72103210
[PyNumber_Add] 0x72103210 + 0x00000008 = 0x72103218
[PyNumber_Power] pow(0x00032a47, 0x00010001, None) = num
[PyNumber_Remainder] num % 0xfffffffd = 0x045ca420
[CompareObj] 0x72103218 == 0x4a30f74d -> False

[PyLong_FromString] int(s, base=16) s=12345678 -> 0x12345678
[PyLong_FromUnicodeObject] int(s, base=16) s=12345678 -> 0x12345678
[PyNumber_Xor] 0x12345678 ^ 0x9e3779b9 = 0x8c032fc1
[PyNumber_And] 0x123456780 & 0xfa3affff = 0x22006780
[PyNumber_Add] 0x22006780 + 0x00000001 = 0x22006781
[PyNumber_Power] pow(0x00118065, 0x00010001, None) = num
[PyNumber_Remainder] num % 0xfffffffd = 0x8c219e43
[CompareObj] 0x22006781 == 0x023a1268 -> False

[PyLong_FromString] int(s, base=16) s=87654321 -> 0x87654321
[PyLong_FromUnicodeObject] int(s, base=16) s=87654321 -> 0x87654321
[PyNumber_Xor] 0x87654321 ^ 0x9e3779b9 = 0x19523a98
[PyNumber_And] 0x876543210 & 0xfa3affff = 0x72103210
[PyNumber_Add] 0x72103210 + 0x00000008 = 0x72103218
[PyNumber_Power] pow(0x00032a47, 0x00010001, None) = num
[PyNumber_Remainder] num % 0xfffffffd = 0x045ca420
[CompareObj] 0x72103218 == 0x88108807 -> False
[CompareObj] 0x00003558 == 0x00003558 -> True

明显的4部分,这不爽多了嘛hhhhhhhhhhhh

调出来一部分看:

1
2
3
4
5
6
7
8
[PyLong_FromString] int(s, base=16) s=12345678 -> 0x12345678
[PyLong_FromUnicodeObject] int(s, base=16) s=12345678 -> 0x12345678
[PyNumber_Xor] 0x12345678 ^ 0x9e3779b9 = 0x8c032fc1
[PyNumber_And] 0x123456780 & 0xfa3affff = 0x22006780
[PyNumber_Add] 0x22006780 + 0x00000001 = 0x22006781
[PyNumber_Power] pow(0x00118065, 0x00010001, None) = num
[PyNumber_Remainder] num % 0xfffffffd = 0x8c219e43
[CompareObj] 0x22006781 == 0x12287f38 -> False

复现的:

1
2
3
input^0x9e3779b9
a1 = (input0 & 0xfa3affff) + 0x00000001
a2 = pow(x,0x00118065,) % 0xfffffffd

真实的:

1
2
第一个返回值:((int(n,16)^2654435769)>>11)**65537%4294967293 
第二个返回值:((int(n,16)<<4)&4198170623)+((n>>5)>>23)

就差几个移位运算,一动态就出,好的,爽!

总结

嗯,除了几个移位或者取值操作捕捉不到,其他的,简直是降维 想tea等常规加密,直接就能看出来,用来trace一下,针不戳

不过还是得动调,不能直接丢弃ida,哎