修改cpython源码实现插桩

修改cpython源码实现插桩

参考

2024 Ciscn长城杯铁人三项 逆向题Cython_[长城杯 2024]cython-CSDN博客

编译

1
git checkout 3.11

修改要的版本

image

直接执行

image

第一次就是有点慢

修改目标

E:\cpython\Objects\abstract.c

测试样例就是ciscn2024的cython题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import ez

flag = "a"*24
flag1 = list(flag)
value = []
b = 0
ck = 0
if len(flag1) == 24:
for i in range(0,len(flag1),4):
b = ord(flag1[i]) << 24 | ord(flag1[i+1]) << 6 | ord(flag1[i+2]) << 8 | ord(flag1[i+3])
value.append(b)

key = [102, 108, 97, 103]
flag_encrypt = []
for i in range(0,6,2):
res = ez.encrypt(value[i],value[i+1],key)
flag_encrypt.append(res)
ck = ez.check(flag_encrypt)
print(ck)

修改a

add

简单加点log试试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

PyObject *
PyNumber_Add(PyObject *v, PyObject *w)
{
PyObject *result = BINARY_OP1(v, w, NB_SLOT(nb_add), "+");
if (result != Py_NotImplemented) {
return result;
}
Py_DECREF(result);

PySequenceMethods *m = Py_TYPE(v)->tp_as_sequence;
if (m && m->sq_concat) {
result = (*m->sq_concat)(v, w);
assert(_Py_CheckSlotResult(v, "+", result != NULL));
return result;
}

return binop_type_error(v, w, "+");
}

改为

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
PyObject *
PyNumber_Add(PyObject *v, PyObject *w)
{
PyObject *result = BINARY_OP1(v, w, NB_SLOT(nb_add), "+");
if (result != Py_NotImplemented) {

if (PyLong_Check(v) && PyLong_Check(w)) {
int overflow_v = 0, overflow_w = 0;
long long new_v = PyLong_AsLongLongAndOverflow(v, &overflow_v);
long long new_w = PyLong_AsLongLongAndOverflow(w, &overflow_w);

if (!overflow_v && !overflow_w) {
printf("0x%llx += 0x%llx\n", new_v, new_w);
} else {
printf("Integer too big to convert: v_overflow=%d, w_overflow=%d\n", overflow_v, overflow_w);
}
} else {
printf("Add: non-integer types v=%s, w=%s\n", Py_TYPE(v)->tp_name, Py_TYPE(w)->tp_name);
}

return result;
}

Py_DECREF(result);

PySequenceMethods *m = Py_TYPE(v)->tp_as_sequence;
if (m && m->sq_concat) {
result = (*m->sq_concat)(v, w);
assert(_Py_CheckSlotResult(v, "+", result != NULL));
return result;
}

return binop_type_error(v, w, "+");
}

这里我只打印了数值的log 拼接逻辑的就没动

image

InPlaceAdd

和上面的逻辑一样

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

PyObject *
PyNumber_InPlaceAdd(PyObject *v, PyObject *w)
{
PyObject *result = BINARY_IOP1(v, w, NB_SLOT(nb_inplace_add),
NB_SLOT(nb_add), "+=");
if (result == Py_NotImplemented) {
PySequenceMethods *m = Py_TYPE(v)->tp_as_sequence;
Py_DECREF(result);
if (m != NULL) {
binaryfunc func = m->sq_inplace_concat;
if (func == NULL)
func = m->sq_concat;
if (func != NULL) {
result = func(v, w);
assert(_Py_CheckSlotResult(v, "+=", result != NULL));

// if (PyLong_Check(v) && PyLong_Check(w)) {
// int overflow_v = 0, overflow_w = 0;
// long long new_v = PyLong_AsLongLongAndOverflow(v, &overflow_v);
// long long new_w = PyLong_AsLongLongAndOverflow(w, &overflow_w);

// if (!overflow_v && !overflow_w) {
// printf("0x%llx += 0x%llx\n", new_v, new_w);
// } else {
// printf("Integer too big to convert: v_overflow=%d, w_overflow=%d\n", overflow_v, overflow_w);
// }
// } else {
// printf("Add: non-integer types v=%s, w=%s\n", Py_TYPE(v)->tp_name, Py_TYPE(w)->tp_name);
// }


return result;
}
}
result = binop_type_error(v, w, "+=");
}


if (PyLong_Check(v) && PyLong_Check(w)) {
int overflow_v = 0, overflow_w = 0;
long long new_v = PyLong_AsLongLongAndOverflow(v, &overflow_v);
long long new_w = PyLong_AsLongLongAndOverflow(w, &overflow_w);

if (!overflow_v && !overflow_w) {
printf("InPlaceAdd: 0x%llx += 0x%llx\n", new_v, new_w);
} else {
printf("InPlaceAdd: Integer too big to convert. v_ovf=%d, w_ovf=%d\n", overflow_v, overflow_w);
}
} else {
printf("InPlaceAdd: Non-integer types: v=%s, w=%s\n", Py_TYPE(v)->tp_name, Py_TYPE(w)->tp_name);
}

return result;
}

image

image

ok进行一下基础的验证

其他

源码

1
2
3
4
5
6
7
8
9
10
11
12
13
#define BINARY_FUNC(func, op, op_name) \
PyObject * \
func(PyObject *v, PyObject *w) { \
return binary_op(v, w, NB_SLOT(op), op_name); \
}

BINARY_FUNC(PyNumber_Or, nb_or, "|")
BINARY_FUNC(PyNumber_Xor, nb_xor, "^")
BINARY_FUNC(PyNumber_And, nb_and, "&")
BINARY_FUNC(PyNumber_Lshift, nb_lshift, "<<")
BINARY_FUNC(PyNumber_Rshift, nb_rshift, ">>")
BINARY_FUNC(PyNumber_Subtract, nb_subtract, "-")
BINARY_FUNC(PyNumber_Divmod, nb_divmod, "divmod()")

这些函数都没有像add的独立的实现都是依靠binary_op来生成 所以处理就很麻烦

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

static PyObject *
binary_op(PyObject *v, PyObject *w, const int op_slot, const char *op_name)
{


// === 日志部分 ===
const char* type_v = Py_TYPE(v)->tp_name;
const char* type_w = Py_TYPE(w)->tp_name;

// 先打印基本类型信息
printf("[binary_op] op: %s, v: %s, w: %s\n", op_name, type_v, type_w);

// 根据不同运算符决定是否打印值
if (PyLong_Check(v) && PyLong_Check(w)) {
int ovf1 = 0, ovf2 = 0;
long long a = PyLong_AsLongLongAndOverflow(v, &ovf1);
long long b = PyLong_AsLongLongAndOverflow(w, &ovf2);
if (!ovf1 && !ovf2) {
if (strcmp(op_name, "^") == 0) {
printf("[XOR] 0x%llx ^ 0x%llx = 0x%llx\n", a, b, a ^ b);
}
else if (strcmp(op_name, "&") == 0) {
printf("[AND] 0x%llx & 0x%llx = 0x%llx\n", a, b, a & b);
}
else if (strcmp(op_name, "|") == 0) {
printf("[OR ] 0x%llx | 0x%llx = 0x%llx\n", a, b, a | b);
}
else if (strcmp(op_name, "<<") == 0) {
printf("[LSHIFT] 0x%llx << 0x%llx = 0x%llx\n", a, b, a << b);
}
else if (strcmp(op_name, ">>") == 0) {
printf("[RSHIFT] 0x%llx >> 0x%llx = 0x%llx\n", a, b, a >> b);
}
else if (strcmp(op_name, "-") == 0) {
printf("[SUB] 0x%llx - 0x%llx = 0x%llx\n", a, b, a - b);
}
else {
// 默认打印
printf("[DEBUG] %s: 0x%llx %s 0x%llx\n", op_name, a, op_name, b);
}
}
}

fflush(stdout); // 确保立即输出






PyObject *result = BINARY_OP1(v, w, op_slot, op_name);
if (result == Py_NotImplemented) {
Py_DECREF(result);

if (op_slot == NB_SLOT(nb_rshift) &&
PyCFunction_CheckExact(v) &&
strcmp(((PyCFunctionObject *)v)->m_ml->ml_name, "print") == 0)
{
PyErr_Format(PyExc_TypeError,
"unsupported operand type(s) for %.100s: "
"'%.100s' and '%.100s'. Did you mean \"print(<message>, "
"file=<output_stream>)\"?",
op_name,
Py_TYPE(v)->tp_name,
Py_TYPE(w)->tp_name);
return NULL;
}
return binop_type_error(v, w, op_name);
}
return result;
}

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

static PyObject *
binary_iop(PyObject *v, PyObject *w, const int iop_slot, const int op_slot,
const char *op_name)
{



PyObject *result = BINARY_IOP1(v, w, iop_slot, op_slot, op_name);
if (result == Py_NotImplemented) {
Py_DECREF(result);
return binop_type_error(v, w, op_name);
}
// === 日志部分 ===
const char* type_v = Py_TYPE(v)->tp_name;
const char* type_w = Py_TYPE(w)->tp_name;

fprintf(stderr, "[binary_iop] op: %s, v type: %s, w type: %s\n",
op_name, type_v, type_w);

// 如果都是整数类型,打印其值和计算结果
if (PyLong_Check(v) && PyLong_Check(w)) {
int ovf1 = 0, ovf2 = 0;
long long a = PyLong_AsLongLongAndOverflow(v, &ovf1);
long long b = PyLong_AsLongLongAndOverflow(w, &ovf2);

if (!ovf1 && !ovf2) {
if (strcmp(op_name, "^=") == 0) {
fprintf(stderr, "[XOR] 0x%llx ^ 0x%llx = 0x%llx\n", a, b, a ^ b);
}
else if (strcmp(op_name, "&=") == 0) {
fprintf(stderr, "[AND] 0x%llx & 0x%llx = 0x%llx\n", a, b, a & b);
}
else if (strcmp(op_name, "|=") == 0) {
fprintf(stderr, "[OR ] 0x%llx | 0x%llx = 0x%llx\n", a, b, a | b);
}
else if (strcmp(op_name, "<<=") == 0) {
fprintf(stderr, "[LSHIFT] 0x%llx << 0x%llx = 0x%llx\n", a, b, a << b);
}
else if (strcmp(op_name, ">>=") == 0) {
fprintf(stderr, "[RSHIFT] 0x%llx >> 0x%llx = 0x%llx\n", a, b, a >> b);
}
else if (strcmp(op_name, "-=") == 0) {
fprintf(stderr, "[SUB] 0x%llx - 0x%llx = 0x%llx\n", a, b, a - b);
}
else {
// 兜底打印
fprintf(stderr, "[DEBUG] %s: 0x%llx %s 0x%llx\n", op_name, a, op_name, b);
}
}
}
return result;
}

我这里是直接根据opname进行判断来选择对应的输出 但是逆天的是没输出左移和右移

image

好歹给个左移和右移吧

image

骚的来了 nnd单独搞他就有输出 一跑pyd直接不走 ida大法 有pdb 大胆调

image

image

逆天的就在这里 这不是有吗为什么不走

image

逆一下题目的dll

image

set ip一下就行了

image

这个pyd不走这个我是没想到的全部patch一下就行了 这里不知道是python版本问题还是说就是这么设计的 其他的运算也可以自己搞搞