Challenge_^平台不支持上传start.sh,bzImage等组件,想要通过运行测试的可以跟我要链接
2026/7/22 18:55:41 网站建设 项目流程

ko文件,直接放ida

_int64 xor_kmod_init()
{
fentry
();
proc_create(“xor_check”, 438, 0, &xor_proc_fops);
printk(&unk_1F0);
return 0;
}
__int64 __fastcall xor_proc_write(__int64 a1, __int64 a2)
{
unsigned __int64 n17_1; // rdx
__int64 n17; // rbx
__int64 n17_2; // rax
BYTE s1[49]; // [rsp-31h] [rbp-31h] BYREF

fentry_(a1, a2);
n17 = 17;
*(QWORD *)&s1[17] = _readgsqword(0x28u);
if ( n17_1 <= 0x11 )
n17 = n17_1;
check_object_size(input_buffer, n17, 0);
if ( copy_from_user(input_buffer, a2, n17) )
return -14;
if ( n17 && input_buffer[n17 - 1] != 10 && n17 == 17 )
{
for ( n17_2 = 0; n17_2 != 17; ++n17_2 )
s1
[n17_2] = input_buffer[n17_2] ^ 0x62;
if ( !memcmp(s1
, &TARGET, 0x11u) )
{
printk(&unk_190);
return 17;
}
else
{
printk(&unk_1C8);
return -22;
}
}
else
{
printk(&unk_168);
return -22;
}
}
__int64 xor_kmod_exit()
{
remove_proc_entry(“xor_check”, 0);
return printk(&unk_234);
}
关键还是在于异或

for ( n17_2 = 0; n17_2 != 17; ++n17_2 )
s1_[n17_2] = input_buffer[n17_2] ^ 0x62;
if ( !memcmp(s1_, &TARGET, 0x11u) )
取target与62进行16进制异或

11 06 12 01 19 10 07 12 15 0C 12 15 0C 1F
sdpc{repwnpwn}
学几个函数

proc_create(“xor_check”, 438, 0, &xor_proc_fops);
它做了以下几件事:

proc_create():这是一个内核函数(别人已经写好的工具函数),作用是在 /proc 目录下创建一个文件。

/proc 是什么?Linux 系统里有一个特殊的目录叫 /proc,它里面的文件不是存在硬盘上的,而是内核虚拟出来的。你读/写这些文件,实际上是在和内核里的代码交互。比如你 cat /proc/cpuinfo 就能看到 CPU 信息。
参数1 “xor_check”:文件的名字。所以这个文件就叫 /proc/xor_check

参数2 438:这个数字是权限,用8进制看就是 0666。6 表示 “读写”,三个数字分别对应 “文件主人/同组人/其他人” 都能读写。这里所有人都可以读写这个文件。

参数3 0:父目录设为空,意味着放在 /proc 根目录下

参数4 &xor_proc_fops:最关键的一个参数。xor_proc_fops 是一个函数表(fops = file operations),这张表里记录了"当有人读这个文件时调用哪个函数"、“当有人写这个文件时调用哪个函数”。& 表示取这个表的地址(告诉内核这张表在哪)。在这个表里,写操作指向的就是下面的 xor_proc_write 函数。

_check_object_size(input_buffer, n17, 0);

_check_object_size():又一个内核安全检查函数
检查 input_buffer(存用户数据的缓冲区)有没有至少 n17 字节那么大,防止越界访问
参数3 的 0 表示这是一个"读"操作检查
if ( copy_from_user(input_buffer, a2, n17) )
return -14;

copy_from_user():把数据从用户空间复制到内核空间
为什么需要这步?系统里有两块"地盘":用户空间(普通程序待的地方)和内核空间(内核代码待的地方)。程序不能直接访问内核的地盘,需要通过 copy_from_user 这个"海关"来传输数据。
参数1 input_buffer:数据要存到内核的哪个位置
参数2 a2:从用户空间的哪个地址取数据
参数3 n17:复制多少个字节
debugme
ida打开

int __fastcall main(int argc, const char **argv, const char **envp)
{
char Str[8]; // [rsp+20h] [rbp-30h] BYREF
__int64 v5; // [rsp+28h] [rbp-28h]
__int64 v6; // [rsp+30h] [rbp-20h]
__int64 v7; // [rsp+38h] [rbp-18h]
char v8; // [rsp+40h] [rbp-10h]

_main();
*(_QWORD *)Str = 0;
v5 = 0;
v6 = 0;
v7 = 0;
v8 = 0;
puts(“Please input the flag: “);
scanf(”%32s”, Str);
if ( strlen(Str) == 32 )
{
decode_flag(&flag);
if ( !memcmp(Str, &flag, 0x20u) )
puts("Right! ");
else
puts("Wrong! ");
}
else
{
puts("Length wrong! ");
}
return 0;
}
在比较处下断点,然后debug,输入任意32个字符,回车

image-20260702143252120

lea rcx, flag ; rcx = &flag (flag 缓冲区的地址)
call decode_flag ; 调用 RC4 解密函数,把加密数据解密到 flag 缓冲区
; 执行完这行后,flag 地址处就是明文 flag 了
lea rax, [rbp+Str] ; rax = 用户输入的字符串地址
mov r8d, 20h ; r8 = 32 (第三个参数:比较长度 32 字节)
lea rdx, flag ; rdx = flag 地址 (第二个参数:解密后的 flag)
mov rcx, rax ; rcx = 用户输入地址 (第一个参数)
call memcmp ; 调用 memcmp(用户输入, 解密后flag, 32)
SDPCSEC{debug_to_do_1s_e53y}
ezida
直接打开然后ctrl+F就能搜到

依旧学习代码

Stream = __iob_func();

__iob_func():获取标准输入/输出/错误流的信息。返回一个结构体数组,其中包含 stdin(键盘输入)、stdout(屏幕输出)等。
Stream 指向 stdin。
fgets(Buffer, 100, Stream);
fgets = “file get string”,从文件读取一行文字。
第一个参数 Buffer → 把读到的内容存入 Buffer 数组。
第二个参数 100 → 最多读 99 个字符(留一个给字符串结尾标记 \0)。
第三个参数 Stream → 从键盘(stdin)读。
效果:你输入一行字按回车,这行字被存进 Buffer。
去掉换行符
Buffer[strcspn(Buffer, “\n”)] = 0;

strcspn(Buffer, “\n”) = “string complement span”,找到 Buffer 里第一个 “\n”(换行符)的位置。
因为你按了回车,fgets 会把换行符也保留在 Buffer 末尾。
例如你输入 abc\n,这个函数返回 3(\n 在第 3 个位置,从 0 开始数)。
Buffer[位置] = 0:把那个位置的换行符替换成 0(也就是字符串结束符 \0),相当于"剪掉换行符"。
检查长度
if ( strlen(Buffer) == correct_len )

strlen(Buffer) = “string length”,数一下 Buffer 里有多少个字符(遇到 \0 停止)。
correct_len:一个事先定义好的全局变量,值是 0x1f = 31。
if (…):如果括号里的条件成立,就执行它下面的代码块;否则跳到 else。
这句话在说:如果你输入的密码长度不等于 31,就去报错。
@WCP@VPhgaL"L&#L r&jL$#Lu"}wn
转16进制,放随波逐流异或

40 57 43 50 40 56 50 68 60 67 61 4c 22 60 4c 26 23 4c 20 72 26 6a 4c 24 23 4c 75 22 7d 77 6e
data = b’@WCP@VPhgaL"L&#L r&jL$#Lu"}wn’
print(bytes([b ^ 19 for b in data]).decode())
go^go=?
解压后只有三个关键文件:

GD1.exe
GD1.console.exe
GD1.pck
这里已经基本能判断是 Godot 导出的 Windows 游戏。原因很简单:

exe + .pck 是 Godot 很典型的发布结构。
调用工具反编译

E:\retools\gdre\gdre_tools.exe --headless
–recover=E:\cod_ctf_nxgodot\NXgodot\GD1.pck
–output=E:\cod_ctf_nxgodot\gdre_recover
或者直接打开E:\retools\gdre\gdre_tools.exe

把附件拖进去查看

重点在main.gdc

extends Node

@export var mob_scene: PackedScene
var score

var a = “000010000010000001101001000010000001000001100110000010000010000001101000000001100110000010010000000001101001000000011001000000011000000000100000000001100100000001100111000001110001000000100011000000010010000001110001000000100010000000100010000000011000000000010010000000100001000000011000000001100111000001100100000000010010000001100100000000010110000000010110000000010111000000010010000000010110000000011000000001101001000000100101000000100010000001101001000001100100000000011000000001101000000000100011000000010111000000010111000010010010\n”

var xor_key = 33

func _ready():
pass

func _process(delta: float) -> void :
pass

func game_over():
$ScoreTimer.stop()
$MobTimer.stop()
$HUD.show_game_over()

func new_game():
score = 0
Player.start(Player.start(Player.start(StartPosition.position)
$StartTimer.start()
$HUD.update_score(score)
$HUD.show_message(“Get Ready”)
get_tree().call_group(“mobs”, “queue_free”)

func _on_mob_timer_timeout():
var mob = mob_scene.instantiate()
var mob_spawn_location = $MobPath / MobSpawnLocation
mob_spawn_location.progress_ratio = randf()
var direction = mob_spawn_location.rotation + PI / 2
mob.position = mob_spawn_location.position
direction += randf_range( - PI / 4, PI / 4)
mob.rotation = direction
var velocity = Vector2(randf_range(150.0, 250.0), 0.0)
mob.linear_velocity = velocity.rotated(direction)
add_child(mob)

func _on_score_timer_timeout():
score += 1
$HUD.update_score(score)

if score == 177906: var result = "" for i in range(0, a.length(), 12): var bin_chunk = a.substr(i, 12) if bin_chunk.length() < 12: break var hundreds = bin_chunk.substr(0, 4).bin_to_int() var tens = bin_chunk.substr(4, 4).bin_to_int() var units = bin_chunk.substr(8, 4).bin_to_int() var mixed_val = hundreds * 100 + tens * 10 + units var decrypted_val = mixed_val ^ xor_key result += String.chr(decrypted_val) $HUD.show_message(result)

func _on_start_timer_timeout():
$MobTimer.start()
$ScoreTimer.start()

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询