1262 words
6 minutes
新开档:逆向

引言#

借不到的爱恋镇楼(我一直在哭)

我对这个模块最初的认知就是以前在某些神秘小游戏改数据的时候用的CE(cheat engine)有印象,但是后面发现其实可以对IoT有所辅助,遂决定开始先往reverse方向学习。但是当我接触reverse的题目的时候,我就发现了一个很大的问题:我的C和py很差,因为大一上学期主要在纯学高数a,且刚放假学的是c++,一进来用ghidra反编译出的代码要么是C要么是python的时候就很绝望,很多逻辑运算都看不懂,自己点开vs code也不知道该敲什么,满脑子的都是include<iostream>… 于是,这篇文章便孕育而生,专门为的服务我这条蛆在忘记某些方面的知识的时候来复习的。 这个模块也是随缘更新的,每学到一些东西便会记录,积累到一定程度便会端上来

C#

strcmp#

strcmp 是 C 语言标准库中的一个字符串比较函数,定义在 <string.h> 头文件中。 比较两个字符串(以 \0 结尾的字符数组)是否相等,或者按照字典序(ASCII 码顺序)判断大小。 比较过程是逐字符进行的,直到遇到第一个不同的字符或遇到字符串结束符 \0。

int strcmp(const char *s1, const char *s2);

返回 0:表示两个字符串相等(s1 和 s2 内容完全相同)。 返回负数:表示 s1 小于 s2(例如 “abc” < “abd”)。 返回正数:表示 s1 大于 s2(例如 “abd” > “abc”)。

builtin_strncpy#

在 Ghidra 的反编译代码里,其实就是我们熟知的 strncpy 函数。

Ghidra 为了准确反映底层调用而使用的一种命名方式

builtin_strncpy(local_7e8,"(34sy_r3v3rs3)",0xf);

意思就是把字符串 “(34sy_r3v3rs3)” 的前 0xf (也就是十进制的 15) 个字符,复制到 local_7e8 这个字符数组里。

builtin_ 前缀#

这是 Ghidra 反编译的一个小特点。当它识别出代码里调用了一个它认为很基础或内建的函数时,就会自动加上 builtin_ 这个前缀。你可以就把它当成一个普通的 strncpy 来理解,在分析代码逻辑时,它的作用完全等同于 strncpy。

gets#

gets 是一个 C 语言标准库函数,用于从标准输入(通常是键盘)读取一行字符串,直到遇到换行符(回车)为止。

gets(locak_58)

它会将读取到的字符串(包括换行符会被自动替换为字符串结束符 \0)存储到 local_58 这个字符数组中。

注意 非常危险,因为它不检查目标缓冲区的大小,如果输入过长会导致缓冲区溢出。但在逆向题中常见。

strlen#

strlen 是 C 语言标准库函数,用于计算字符串的长度(不包括结尾的 \0)。

sVar1 = strlen(local_58); local_10 = (int)sVar1;

这里将 local_58 字符串的长度计算出来,赋值给变量 sVar1。 然后将 sVar1 强制转换为 int 类型,然后赋值给 local_10。

python#

len#

for i in range(len(list))

表示循环次数等于列表长度

运算符#

& 按位与#

两个二进制位都为1时,结果才为1,否则为0。

操作过程:

5 & 3

5: 0 1 0 1

3: 0 0 1 1

结果: 0 0 0 1

结果为1(0001)

| 按位或#

两个二进制位只要有一个为1,结果就为1,操作过程同上

5 | 3 -> 0111 -> 7

^ 按位异或#

两个二进制位不同则为1,相同则为0,操作过程同上

5 ^ 3 -> 0110 -> 6

~ 按位取反#

将每一位取反(0变1,1变0),操作过程同上。

注意在Python中,结果是补码形式,可能得到负数,不过初学可以先放一放。

<< 左移#

将二进制位整体向左移动,右边低位补0。

每左移一位,相当于乘以2。

5 << 1

0101 -> 1010 -> 10(5*2)

5 << 3

0101 -> 0101000 ->40(522*2)

>> 右移#

将二进制位整体向右移动,左边高位补0(对于非负数)。操作同上,生活不顺心大可以换成十进制计算后再换成二进制以达到目标。

每右移一位,相当于除以2取整。

[a:]#

作用:切片操作,从字符串的第 a 个字符开始取,即去掉开头的 '0x''0x61'[2:]'61''0xa'[2:]'a'

+=

ord#

将字符转换为其对应的 Unicode 码点(整数)。

ord(A) -> 65

hex#

将整数转换成十六进制字符串,格式为0x...

hex(97) -> 0x61

hex(10) -> 0xa

str#

将结果转换为字符串

str()

.zfill(a)#

用零在左侧填充到指定宽度(这里是 a)。如果字符串长度不足 a 位,就在左边补零;如果已经 a 位或以上,则不变

'a'.zfill(2)'0a''61'.zfill(2)'61'

现在来理解这样一段([题源 2021 新生赛]简简单单的逻辑)

flag = 'xxxxxxxxxxxxxxxxxx'
list = [47, 138, 127, 57, 117, 188, 51, 143, 17, 84, 42, 135, 76, 105, 28, 169, 25]
result = ''
for i in range(len(list)):
key = (list[i]>>4)+((list[i] & 0xf)<<4)
result += str(hex(ord(flag[i])^key))[2:].zfill(2)
print(result)
# result=bcfba4d0038d48bd4b00f82796d393dfec

就先这样?

新开档:逆向
https://dxfaker.top/posts/26228/
Author
dxfaker
Published at
2026-02-28
License
CC BY-NC-SA 4.0

Some information may be outdated