感谢@shimly清风师傅提供的题目
提交最小解即可,4位值
下载下来一个r3.r3文件,拖到ida中运行,是64位的,main函数并不是很复杂
strncpy(dest, v19, len - 6);
前面看着都还行,就是简单的赋值输入打印,但是strncpy这个地方让我有点奇怪,前面也没给v19赋值,这里怎么copy啊,回去看下地址,这里s的长度限制为5*sizeof(char),那么scanf多出来的就会覆盖到v19上
那么这行代码就可以这么转换,也就是取出了flag{}包裹的字符串
# v19就相当于是
v19 = s[5:]
# len(v19) = len(s)-5
# len - 6 = len(s) - 6 = len(v19) - 1
# strncpy(dest, v19, len - 6);就相当于
dest = s[5:-1]
__isoc99_sscanf(dest, "%x", &v5);
这行代码也不是很懂,问了下gpt,主要作用就是把dest以十六进制转成数字赋值给v5,其实就是把flag转为数字
这行代码是在C语言中使用的,其功能是从字符串
dest
中按照%x
的格式字符串提取一个十六进制的数值,并将这个数值赋给变量v5
具体来说:
__isoc99_sscanf
是C语言中的一个函数,它与sscanf
函数类似,都是用于从一个字符串中按照指定的格式字符串提取数据的dest
是需要从中提取数据的字符串"%x"
是一个格式字符串,它告诉__isoc99_sscanf
函数,从dest
字符串中提取的是一个十六进制的数值&v5
是一个指针,指向变量v5
的内存地址。这样,提取出的十六进制数值就会被赋值给v5
所以,这行代码的整体含义是:从字符串
dest
中按照十六进制的格式提取一个数值,并赋给变量v5
赋值
根据上面一步,这个地方的赋值其他都是固定的值,只有v5是变化的
循环
根据上一步得出的结论,可以知道v17前6个值都是固定的,那么循环前五次的结果也是固定的
这个地方建议用ida的动态调试去看,提示中给出值为4位,那么就假设给的flag是flag{0000},调出来发现,i=6时,v16的值是000000000000E560,v17[6]=v5,那么v16+v5结果等于0xFFFF,退出循环,然后判断成功,所以v5=0xFFFF-v16=0x1A9F,提示也要求最小值,成功
提交flag也是成功,flag为:
flag{1a9f}
ida动态调试可能遇到的问题
ida不显示对应的debugger
不知道咋的,ida很久没用,突然debug选项少了remote windows debugger,网上几乎没有找到相关的信息,更多的是利用windbg,比如IDA win10 找不到 windbg 解决方案,不过讲的还行,有知道咋回事的大佬可以评论留言一下,感谢
我看到还支持Remote Linux debugger,就是IDA目录下面,找dbgsrv目录,下面有两个linux的,一般来说选64位的,可以尝试一下,拖到Linux系统下运行就行
zsh: permission denied
执行以下命令后,报错 zsh: permission denied
./linux_server64
# zsh: permission denied: ./linux_server64
这个是因为用户对这个文件没有权限,需要添加权限
chmod u+x linux_server64
chmod是权限管理命令change the permissions mode of a file的缩写
u代表所有者。x代表执行权限。’+’ 表示增加权限
chmod u+x linux_server64 就表示对当前目录下的file.sh文件的所有者增加可执行权限
分析的程序也要放入linux
文件先加载到ida中,debugger没有配置,用的是文件默认的值,然后就会提示报错,但是最后有个框弹出来确认以后,会自动传到虚拟机里,这个不知道为什么
后面再尝试的时候,会提示application和inputfile为空,然后焦点会在parameter上,后面又尝试了一下,又不需要了,有点奇怪的
注意,Hostname要填虚拟机的ip地址
自己在win下用ida分析,分析时间长了,就想用python写脚本跑一下
win下无法执行源程序,就想着换语言重写程序,甚至拖到linux运行写的程序
就是没想到在linux下运行源程序,找了大佬的博客,还奇怪人家怎么写的那么好,跟ida上伪代码几乎一模一样,结果还很快就出来了
REVERSE-PRACTICE-CTFSHOW-2_ctfshow reverse 武穆遗书-CSDN博客
https://www.cnblogs.com/ethan269/p/ctfshow_re3.html
自己写了脚本,跑俩小时还在i=3,电脑都发烫了
#include <stdio.h>
#include <string.h>
#include <stdint.h> // 引入 stdint.h 以便使用 uint64_t
int main() {
// Initialize variables
uint32_t v7 = 80;
uint32_t v8 = 64227;
uint32_t v9 = 226312059;
uint32_t v10 = 1540056586; // 将负数转换为正数
uint32_t v11 = 5;
uint32_t v12 = 16;
uint32_t v13 = 3833;
uint32_t v5 = 0;
uint64_t v16 = 0; // 使用 uint64_t 类型
printf("plz input the key:\n");
char s[100];
scanf("%s", s);
// printf("%s\n", s);
char dest[100];
strncpy(dest, &s[5], strlen(s) - 6); // 复制从第5个字符开始的部分
dest[strlen(s) - 6] = '\0'; // 添加字符串结束符
printf("%s\n", dest);
// 将十六进制字符串转换为整数
sscanf(dest, "%x", &v5);
printf("%u\n", v5);
uint32_t v17[] = {v7, v8, v9, v10, (v11 << 12) + v12, v13, v5};
printf("[%u, %u, %u, %u, %u, %u, %u]\n", v17, v17[1], v17[2], v17[3], v17[4], v17[5], v17[6]);
for (size_t i = 0; i < sizeof(v17); ++i) {
v16 += v17[i];
while (v16 > 0xFFFF) {
uint32_t v15 = v16 >> 16;
v16 = v15 + v16;
// v16 = v16 % ((uint64_t)1 << 64); // 对2的64次方取余
v16 &= 0xFFFFFFFFFFFFFFFF;
}
printf("%d: %d\n", i, v16);
}
if (v16 == 0xFFFF) {
printf("OK\n");
} else {
printf("Error\n");
}
return 0;
}