攻防世界reverse难度3

news/2025/1/31 3:36:06/文章来源:https://www.cnblogs.com/T0fV404/p/18694564

攻防世界Reverse3

哎,坐牢,哎,坐牢.

我从来没有觉得ctf有趣过.jpg

painful

secret-string-400

js虚拟机混淆

我理解错了,一直以为是所有代码翻译一遍.

结果发现是读取字节然后执行代码.

也就是说,它可以直接翻译成ascii码去掉无用的字节码.(还是看wp知道的,看的时候都懵了,为什么可以直接翻译,思维迪化了)

print(bytes([11, 1, 79, 98, 106, 101, 99, 116, 0, 12, 1, 120, 0, 114, 101, 116, 117, 114, 110, 32, 100, 111, 99, 117, 109, 101, 110, 116, 46, 103, 101, 116, 69, 108, 101, 109, 101, 110, 116, 115, 66, 121, 84, 97, 103, 78, 97, 109, 101, 40, 39, 105, 110, 112, 117, 116, 39, 41, 91, 48, 93, 46, 118, 97, 108, 117, 101, 47, 47, 0, 15, 3, 1, 120, 0, 14, 3, 1, 117, 115, 101, 114, 105, 110, 112, 117, 116, 0, 12, 1, 121, 0, 119, 105, 110, 100, 111, 119, 46, 109, 97, 99, 104, 105, 110, 101, 46, 101, 110, 100, 32, 61, 32, 102, 117, 110, 99, 116, 105, 111, 110, 40, 41, 123, 116, 104, 105, 115, 46, 99, 111, 100, 101, 61, 91, 93, 59, 116, 104, 105, 115, 46, 80, 67, 61, 49, 55, 51, 125, 47, 47, 0, 15, 3, 1, 121, 0, 12, 1, 122, 0, 97, 108, 101, 114, 116, 40, 49, 41, 59, 47, 47, 11, 234, 79, 98, 106, 101, 99, 116, 255, 9, 255, 255, 255, 12, 10, 97, 108, 101, 114, 116, 40, 50, 41, 59, 47, 47, 12, 234, 120, 255, 118, 97, 114, 32, 102, 61, 119, 105, 110, 100, 111, 119, 46, 109, 97, 99, 104, 105, 110, 101, 46, 114, 101, 103, 105, 115, 116, 101, 114, 115, 91, 49, 93, 46, 117, 115, 101, 114, 105, 110, 112, 117, 116, 47, 47, 10, 118, 97, 114, 32, 105, 32, 61, 32, 102, 46, 108, 101, 110, 103, 116, 104, 47, 47, 10, 118, 97, 114, 32, 110, 111, 110, 99, 101, 32, 61, 32, 39, 103, 114, 111, 107, 101, 39, 59, 47, 47, 10, 118, 97, 114, 32, 106, 32, 61, 32, 48, 59, 47, 47, 10, 118, 97, 114, 32, 111, 117, 116, 32, 61, 32, 91, 93, 59, 47, 47, 10, 118, 97, 114, 32, 101, 113, 32, 61, 32, 116, 114, 117, 101, 59, 47, 47, 10, 119, 104, 105, 108, 101, 40, 106, 32, 60, 32, 105, 41, 123, 47, 47, 10, 111, 117, 116, 46, 112, 117, 115, 104, 40, 102, 46, 99, 104, 97, 114, 67, 111, 100, 101, 65, 116, 40, 106, 41, 32, 94, 32, 110, 111, 110, 99, 101, 46, 99, 104, 97, 114, 67, 111, 100, 101, 65, 116, 40, 106, 37, 53, 41, 41, 47, 47, 10, 106, 43, 43, 59, 47, 47, 10, 125, 47, 47, 10, 118, 97, 114, 32, 101, 120, 32, 61, 32, 32, 91, 49, 44, 32, 51, 48, 44, 32, 49, 52, 44, 32, 49, 50, 44, 32, 54, 57, 44, 32, 49, 52, 44, 32, 49, 44, 32, 56, 53, 44, 32, 55, 53, 44, 32, 53, 48, 44, 32, 52, 48, 44, 32, 51, 55, 44, 32, 52, 56, 44, 32, 50, 52, 44, 32, 49, 48, 44, 32, 53, 54, 44, 32, 53, 53, 44, 32, 52, 54, 44, 32, 53, 54, 44, 32, 54, 48, 93, 59, 47, 47, 10, 105, 102, 32, 40, 101, 120, 46, 108, 101, 110, 103, 116, 104, 32, 61, 61, 32, 111, 117, 116, 46, 108, 101, 110, 103, 116, 104, 41, 32, 123, 47, 47, 10, 106, 32, 61, 32, 48, 59, 47, 47, 10, 119, 104, 105, 108, 101, 40, 106, 32, 60, 32, 101, 120, 46, 108, 101, 110, 103, 116, 104, 41, 123, 47, 47, 10, 105, 102, 40, 101, 120, 91, 106, 93, 32, 33, 61, 32, 111, 117, 116, 91, 106, 93, 41, 47, 47, 10, 101, 113, 32, 61, 32, 102, 97, 108, 115, 101, 59, 47, 47, 10, 106, 32, 43, 61, 32, 49, 59, 47, 47, 10, 125, 47, 47, 10, 105, 102, 40, 101, 113, 41, 123, 47, 47, 10, 97, 108, 101, 114, 116, 40, 39, 89, 79, 85, 32, 87, 73, 78, 33, 39, 41, 59, 47, 47, 10, 125, 101, 108, 115, 101, 123, 10, 97, 108, 101, 114, 116, 40, 39, 78, 79, 80, 69, 33, 39, 41, 59, 10, 125, 125, 101, 108, 115, 101, 123, 97, 108, 101, 114, 116, 40, 39, 78, 79, 80, 69, 33, 39, 41, 59, 125, 47, 47, 255, 9, 255, 255, 255, 12, 10, 97, 108, 101, 114, 116, 40, 51, 41, 59, 47, 47, 15, 1, 234, 120, 255, 9, 255, 255, 255, 12, 10, 97, 108, 101, 114, 116, 40, 52, 41, 59, 47, 47, 10, 97, 108, 101, 114, 116, 40, 53, 41, 59, 47, 47, 10, 97, 108, 101, 114, 116, 40, 54, 41, 59, 47, 47, 10, 97, 108, 101, 114, 116, 40, 55, 41, 59, 47, 47, 0, 12, 1, 103, 0, 118, 97, 114, 32, 105, 32, 61, 48, 59, 119, 104, 105, 108, 101, 40, 105, 60, 119, 105, 110, 100, 111, 119, 46, 109, 97, 99, 104, 105, 110, 101, 46, 99, 111, 100, 101, 46, 108, 101, 110, 103, 116, 104, 41, 123, 105, 102, 40, 119, 105, 110, 100, 111, 119, 46, 109, 97, 99, 104, 105, 110, 101, 46, 99, 111, 100, 101, 91, 105, 93, 32, 61, 61, 32, 50, 53, 53, 32, 41, 32, 119, 105, 110, 100, 111, 119, 46, 109, 97, 99, 104, 105, 110, 101, 46, 99, 111, 100, 101, 91, 105, 93, 32, 61, 32, 48, 59, 105, 43, 43, 125, 47, 47, 0, 12, 1, 104, 0, 119, 105, 110, 100, 111, 119, 46, 109, 97, 99, 104, 105, 110, 101, 46, 80, 67, 61, 49, 55, 50, 47, 47, 0, 15, 0, 1, 103, 0, 15, 0, 1, 104, 0]).split(b'\x00'))

[b'\x0b\x01Object',
b'\x0c\x01x',
b"return document.getElementsByTagName('input')[0].value//",
b'\x0f\x03\x01x',
b'\x0e\x03\x01userinput',
b'\x0c\x01y',
b'window.machine.end = function(){this.code=[];this.PC=173}//',
b'\x0f\x03\x01y',
b'\x0c\x01z',
b"alert(1);//\x0b\xeaObject\xff\t\xff\xff\xff\x0c\nalert(2);//\x0c\xeax\xffvar
f=window.machine.registers[1].userinput//\nvar i = f.length//\nvar nonce =
'groke';//\nvar j = 0;//\nvar out = [];//\nvar eq = true;//\nwhile(j < i)
{//\nout.push(f.charCodeAt(j) ^ nonce.charCodeAt(j%5))//\nj++;//\n}//\nvar ex =
[1, 30, 14, 12, 69, 14, 1, 85, 75, 50, 40, 37, 48, 24, 10, 56, 55, 46, 56,
60];//\nif (ex.length == out.length) {//\nj = 0;//\nwhile(j < ex.length)
{//\nif(ex[j] != out[j])//\neq = false;//\nj += 1;//\n}//\nif(eq){//\nalert('YOU
WIN!');//\n}else{\nalert('NOPE!');\n}}else{alert('NOPE!');}//\xff\t\xff\xff\xff\
x0c\nalert(3);//\x0f\x01\xeax\xff\t\xff\xff\xff\x0c\nalert(4);//\nalert(5);//\na
lert(6);//\nalert(7);//",
b'\x0c\x01g',
b'var i =0;while(i<window.machine.code.length){if(window.machine.code[i] == 255
) window.machine.code[i] = 0;i++}//',
b'\x0c\x01h',
b'window.machine.PC=172//',
b'\x0f',
b'\x01g',
b'\x0f',
b'\x01h',
b'']

整理可得

f = window.machine.registers[1].userinput//
var i = f.length
var nonce = 'groke';
var j = 0;
var out = [];
var eq = true;
while (j < i) {
out.push(f.charCodeAt(j) ^ nonce.charCodeAt(j % 5))
j++;
}
var ex = [1, 30, 14, 12, 69, 14, 1, 85, 75, 50, 40, 37, 48, 24, 10, 56, 55, 46,
56, 60];
if (ex.length == out.length) {
j = 0;
while (j < ex.length) {
if (ex[j] != out[j])
eq = false;
j += 1;
}
if (eq) {
alert('YOU WIN!');
} else {
alert('NOPE!');
}
} else {
alert('NOPE!');
}

exp:

key1=[1, 30, 14, 12, 69, 14, 1, 85, 75, 50, 40, 37, 48, 24, 10, 56, 55, 46, 56, 60]
key2="groke"
flag=""
for i in range(len(key1)):flag+=chr(key1[i]^ord(key2[i%5]))
print(flag) # flag = WOW_so_EASY

Catch-me

要爆破


攻防世界逆向高手题之catch-me_catch-me 攻防世界-CSDN博客

在这里插入图片描述

照例下载附件,结果两次都提示是用7z打开(解压),所以要解压两次才能得到真正文件:
在这里插入图片描述
最后得到的文件是一个64位的ELF文件:
在这里插入图片描述
照例运行一下程序查看主要回显信息:
在这里插入图片描述

(这里积累第一个经验)
啥也没输入就直接程序结束了,回顾一下前面做的不用输入的类型,那时检查文件中flag的,而且没有对应文件就闪退的。
在这里插入图片描述
那么这题也是不用输入的,这种不用输入的程序都是直接利用程序外部的一些东西来作为条件继续执行的,所以我们这次也是要修改程序外的一些东西,来符合程序的执行。

照例扔入64IDA中查看main函数逻辑:

(这里积累第二个经验)
积累一些函数的利用:
int _mm_cvtsi128_si32 (__m128i a);
返回值:r := a0
_mm_add_epi32(a, b);
返回值:a+b
__m128i _mm_slli_si128 (__m128i a, int imm);
4字节128位移位操作
返回值:r := a << (imm * 8)
__m128i _mm_unpackhi_epi16 (__m128i a, __m128i b);
将 a 中的高 4 个有符号或无符号 16 位整数与 b 中的高 4 个有符号或无符号 16 位整数交错。a在前,b在后。
返回值:
r0 := a4 ; r1 := b4
r2 := a5 ; r3 := b5
r4 := a6 ; r5 := b6
r6 := a7 ; r7 := b7
__m128i _mm_unpacklo_epi16 (__m128i a, __m128i b);
将 a 中的低 4 个有符号或无符号 16 位整数与 b 中的低 4 个有符号或无符号 16 位整数交错。a在前,b在后。
返回值:
r0 := a0 ; r1 := b0
r2 := a1 ; r3 := b1
r4 := a2 ; r5 := b2
r6 := a3 ; r7 := b3
__m128i _mm_unpacklo_epi8 (__m128i a, __m128i b);
将 a 中的低 8 个有符号或无符号 8 位整数与 b 中的低 8 个有符号或无符号 8 位整数交错。a在前,b在后。
返回值:
r0 := a0 ; r1 := b0
r2 := a1 ; r3 := b1

r14 := a7 ; r15 := b7
__m128i _mm_unpackhi_epi8 (__m128i a, __m128i b);
将 a 中的高 8 个有符号或无符号 8 位整数与 b 中的高 8 个有符号或无符号 8 位整数交错。a在前,b在后。
返回值:
r0 := a8 ; r1 := b8
r2 := a9 ; r3 := b9

r14 := a15 ; r15 := b15
__m128i _mm_load_si128 (__m128i *p);
加载 128 位值。
返回值:
返回加载到代表寄存器的变量中的值,地址 p 必须是 16 字节对齐的。
char *getenv(const char *name)函数:(get environment)
搜索 name 所指向的环境字符串,并返回相关的值。

在这里插入图片描述

(这里积累第三个经验)
所以在前面v3是直接生成的,这里能获取程序外部的只有getenv函数,那么关键地方就是这里if ( getenv("ASIS") && (*(_DWORD *)getenv("CTF") ^ v3) == 0xFEEBFEEB )

v3动态调试发现值是0xB11924E1,那么我们要设置满足条件的ASISCTF环境变量才能执行if语句,才有可能获取flag

这里其实很多其它博客都忽略了一点就是getenv("ASIS")应该是要爆破出来的,首先附上C语言运算符的优先级,从图中可以看出只要前面(*(_DWORD *)getenv("CTF") ^ v3) == 0xFEEBFEEB满足,那么后面getenv("ASIS")只要不是0就可以。

(注意这里&&不要和&位运算搞混了,&&是逻辑与,&是位与。)
在这里插入图片描述
getenv(“CTF”)=0xFEEBFEEB^v3,可以算出等于0x4ff2da0a,那么getenv("ASIS")是多少呢?只能猜测它和getenv("CTF")一样都是0x4ff2da0a试一试了。
(这里积累第四个经验)
所以我们导入linux的环境变量,这里也补充一些基本知识:(注意:export只能在当前终端中有效,终端关闭就没用了)

(通过printf可以导入十六进制整数类型,值得积累)
export ASIS="$(printf "\x0a\xda\xf2\x4f")" #注意参数是从低位到高位的
export CTF="$(printf "\x0a\xda\xf2\x4f")"

在这里插入图片描述
然后直接运行,果不其然getenv("ASIS")等于getenv("CTF"),得出真实的flag了:
在这里插入图片描述 (这里积累第5个经验)
另一种方法就是我们既然知道了getenv("ASIS")的值,我们也可以直接自己生成flag啊。

首先第一个要注意的是v30xB11924E1本来应该是小端顺序逆序存储在内存中的,可是这里红框中HIBYTE、BYTE2、BYTE1、BYTE直接把v3按大端顺序存储了,这点要特别注意,而且还经过了位与&处理。

然后就是黄框中在v3数组后拼接小端getenv("ASIS"),最后我们直接用Export data直接导出haystack原始的32位值进行处理即可。
在这里插入图片描述
附上脚本,注意源代码中是[i & 7]差点看错成[i % 7]了:

key1=0xFEEBFEEB key2=0xB11924E1key3=key1^key2 #0x4ff2da0a
print(hex(key3&(key3^key2)))
list1=[0xb1,0x19&0xfd,0x24&0xdf,0xe1&0xbf,0x0a,0xda,0xf2,0x4f]#v3按大端顺序被截取了
flag=[ 0x87, 0x29, 0x34, 0xC5, 0x55, 0xB0, 0xC2, 0x2D, 0xEE, 0x60, 0x34, 0xD4, 0x55, 0xEE, 0x80, 0x7C,0xEE, 0x2F, 0x37, 0x96, 0x3D, 0xEB,0x9C, 0x79, 0xEE, 0x2C, 0x33, 0x95, 0x78, 0xED, 0xC1, 0x2B]
for i in range(32): 					       flag[i]^=list1[i&7]print('ASIS{'+''.join(map(chr,flag))+'}')

结果:
在这里插入图片描述
总结:

1:
(这里积累第一个经验)
啥也没输入就直接程序结束了,回顾一下前面做的不用输入的类型,那时检查文件中flag的,而且没有对应文件就闪退的。
在这里插入图片描述
那么这题也是不用输入的,这种不用输入的程序都是直接利用程序外部的一些东西来作为条件继续执行的,所以我们这次也是要修改程序外的一些东西,来符合程序的执行。

2:
(这里积累第三个经验)
所以在前面v3是直接生成的,这里能获取程序外部的只有getenv函数,那么关键地方就是这里if ( getenv("ASIS") && (*(_DWORD *)getenv("CTF") ^ v3) == 0xFEEBFEEB )
.
v3动态调试发现值是0xB11924E1,那么我们要设置满足条件的ASISCTF环境变量才能执行if语句,才有可能获取flag
.
这里其实很多其它博客都忽略了一点就是getenv("ASIS")应该是要爆破出来的,首先附上C语言运算符的优先级,从图中可以看出只要前面(*(_DWORD *)getenv("CTF") ^ v3) == 0xFEEBFEEB满足,那么后面getenv("ASIS")只要不是0就可以。
.
(注意这里&&不要和&位运算搞混了,&&是逻辑与,&是位与。)
.在这里插入图片描述

3:
(这里积累第四个经验)
所以我们导入linux的环境变量,这里也补充一些基本知识:(注意:export只能在当前终端中有效,终端关闭就没用了)

在这里插入图片描述

(通过printf可以导入十六进制整数类型,值得积累)export ASIS="$(printf "\x0a\xda\xf2\x4f")" #注意参数是从低位到高位的export CTF="$(printf "\x0a\xda\xf2\x4f")" 1234

4:
(这里积累第5个经验)
另一种方法就是我们既然知道了getenv("ASIS")的值,我们也可以直接自己生成flag啊。
首先第一个要注意的是v30xB11924E1本来应该是小端顺序逆序存储在内存中的,可是这里红框中HIBYTE、BYTE2、BYTE1、BYTE直接把v3按大端顺序存储了,这点要特别注意,而且还经过了位与&处理。
然后就是黄框中在v3数组后拼接小端getenv("ASIS"),最后我们直接用Export data直接导出haystack原始的32位值进行处理即可。

解毕!敬礼!

re5-packed-movement

先脱壳

然后发现是mov混淆

然后在每一次出现Wrong flag的地方找字节码

ALEXCTF{M0Vfusc4t0r_w0rk5_l1ke_m4g1c}

deedeedee

神经病题目,用一个叫做D语言写的,一个估计是源码,一个是二进制文件,然后flag就在源码里.

然后我看其他wp是靠动调做出来的,都是神人感觉这么好,我调了半天没搞出来,只能大概定位.

key

攻防世界逆向高手题的key_攻防世界逆向key题解-CSDN博客
主要是参考这篇,还是太急和经验不足了

首先遇到不需要输入的题,那就说明是内部解决的.

但是这题不是,应该先shift+f12的,可以看到一个字符串写着flag.txt

过去一看是打开文件,那么这题就是打开文件的获取输入.

接着我们就可以把关闭文件的地方找出来了

image-20250124184623918

那么下面就肯定是比较了

image-20250124184644895

这里就是加密和判断文件有无打开

image-20250124184721529

然后有几个槽点,就是我这里的加密循环是少一个参数的,我怎么y都不出来,导致我看不懂它的逻辑.动调发现是异或和相加,但是我不知道为什么处理Block的去处理v29了,另一个也反过来了,太奇怪了.(解决了,出现三个参数后就好看多了,一下子明白了)

经验:

其实还有学到三点很重要.

一个就是要根据前面的点把一些代码段的功能猜出来,这样就减少范围了,很舒服.

还有就是追踪重要参数,我要改变我的习惯了,不要一开始追踪参数,后面就没有耐心了,应该是着重注意加密函数和比较函数的参数.

经过学长提示,这里的void*极有可能是结构体,我后面构造了一个,ida直接把这些void*变成结构体了

这题是好题,足够复杂.

2ex1

mips的架构,但是可以看出来是base64,dump出key,但是不知道为什么cyberchef不能用,估计是我理解错了做法,毕竟不熟悉base系列,所以最后还是copy别人的脚本获得flag,不过思路对了.

梅津美治郎

这题虽然做出来了,但是其实不是很理解,看了wp恍然大悟.

int __cdecl main(int argc, const char **argv, const char **envp)
{const CHAR *v3; // ebxHMODULE ModuleHandleA; // eaxvoid (__stdcall *ProcAddress)(HMODULE, LPCSTR); // eaxchar Str1[20]; // [esp+1h] [ebp-157h] BYREFchar Str2[11]; // [esp+15h] [ebp-143h] BYREFint v9; // [esp+20h] [ebp-138h] BYREF_DWORD v10[6]; // [esp+26h] [ebp-132h] BYREF__int16 v11; // [esp+3Eh] [ebp-11Ah]_DWORD v12[7]; // [esp+40h] [ebp-118h] BYREF_DWORD v13[4]; // [esp+5Ch] [ebp-FCh] BYREF_DWORD v14[2]; // [esp+6Ch] [ebp-ECh] BYREFchar v15; // [esp+74h] [ebp-E4h]_DWORD v16[8]; // [esp+75h] [ebp-E3h] BYREF__int16 v17; // [esp+95h] [ebp-C3h]_DWORD v18[8]; // [esp+97h] [ebp-C1h] BYREFchar v19; // [esp+B7h] [ebp-A1h]int v20; // [esp+B8h] [ebp-A0h] BYREF_DWORD v21[8]; // [esp+BEh] [ebp-9Ah] BYREFchar v22; // [esp+DEh] [ebp-7Ah]_DWORD v23[8]; // [esp+DFh] [ebp-79h] BYREF__int16 v24; // [esp+FFh] [ebp-59h]int v25; // [esp+101h] [ebp-57h]int v26; // [esp+105h] [ebp-53h]char v27; // [esp+109h] [ebp-4Fh]_DWORD v28[4]; // [esp+10Ah] [ebp-4Eh] BYREF_DWORD v29[7]; // [esp+11Ah] [ebp-3Eh] BYREF_DWORD v30[6]; // [esp+136h] [ebp-22h] BYREF__int16 v31; // [esp+14Eh] [ebp-Ah]int *p_argc; // [esp+150h] [ebp-8h]p_argc = &argc;sub_402940();puts("            .     \n""           _|_    ROBOTIC AUTHENTICATION SYSTEM\n""    /\\/\\  (. .)  /\n""    `||'   |#|  \n""     ||__.-\"-\"-.___   \n""     `---| . . |--.\\  \n""         | : : |  ,||,\n""         `..-..'  \\/\\/\n""          || ||   \n""          || ||    \n""         |__|__|  \n");v20 = 1337;qmemcpy(v21, "Qmd`rd!douds!uid!ghsru!Q`rrvnse;", sizeof(v21));v22 = 1;qmemcpy(v18, "Qmd`rd!douds!uid!ghsru!Q`rrvnse;", sizeof(v18));v19 = 1;qmemcpy(v23, "Qmd`rd!douds!uid!rdbnoe!Q`rrvnse", sizeof(v23));v24 = 315;qmemcpy(v16, "Qmd`rd!douds!uid!rdbnoe!Q`rrvnse", sizeof(v16));v17 = 315;v25 = 1869557876;v26 = 1718432615;v27 = 3;v14[0] = 1869557876;v14[1] = 1718432615;v15 = 3;qmemcpy(v28, "jdsodm23/emm", 12);v28[3] = 20906241;qmemcpy(v13, "jdsodm23/emm", 12);v13[3] = 20906241;qmemcpy(v29, "@eeWdbunsdeDybdquhnoI`oe", 24);v29[6] = 24339565;qmemcpy(v12, "@eeWdbunsdeDybdquhnoI`oe", 24);v12[6] = 24339565;qmemcpy(v30, "Xnt!vho/!Bnofs`utm`uhnor", sizeof(v30));v31 = 288;qmemcpy(v10, "Xnt!vho/!Bnofs`utm`uhnor", sizeof(v10));v11 = 288;v9 = 1337;strcpy(Str2, "r0b0RUlez!");dword_40AD94 = (int)&v9;dword_40ADA0 = (int)&v20;dword_40AD8C = (char *)v18;dword_40AD90 = (char *)v16;dword_40AD98 = (int)v14;lpProcName = (LPCSTR)v12;lpModuleName = (LPCSTR)v13;Buffer = (char *)v10;sub_401500(0);v3 = lpProcName;ModuleHandleA = GetModuleHandleA(lpModuleName);ProcAddress = (void (__stdcall *)(HMODULE, LPCSTR))GetProcAddress(ModuleHandleA, v3);ProcAddress((HMODULE)1, (LPCSTR)sub_40157F);puts(dword_40AD8C);scanf("%20s", Str1);if ( !strcmp(Str1, Str2) ){puts("You passed level1!");sub_4015EA(0);}return 0;

开头可以看到一堆数字赋值,但是r了后并不是正常的字符串,然后我们能看到下面有个 sub_401500(0);里面是:

int __cdecl sub_401500(int a1)
{int result; // eax_BYTE *i; // [esp+1Ch] [ebp-Ch]if ( a1 <= 9 )return sub_401500(a1 + 1);for ( i = (_BYTE *)dword_40AD94; ; ++i ){result = dword_40ADA0;if ( (unsigned int)i >= dword_40ADA0 )break;*i ^= 1u;}return result;
}

这里对字符串处理了,最后变成AddVectoredExceptionHandler这是个异常处理函数,甚至比SEH优先级还高,接着的GetModuleHandleAGetProcAddress获取到它的地址,然后执行ProcAddress((HMODULE)1, (LPCSTR)sub_40157F);我当时还纳闷怎么变量还能当函数用,还是经验太少.这个sub_40157F就是异常处理跳转到的函数,先不管.

接下来是第一个输入输出sub_4015EA,直接copystr2pass掉,看看函数里面:

int __cdecl sub_4015EA(int a1)
{if ( a1 <= 9 )return sub_4015EA(a1 + 1);puts(dword_40AD90);dword_40ADA8 = 4199961;__debugbreak();return 0;
}

有个__debugbreak()用来触发异常,我还以为是反调试😓,然后就是sub_40157F:

void __cdecl __noreturn sub_40157F(int a1)
{_BYTE v1[20]; // [esp+18h] [ebp-20h] BYREFint v2; // [esp+2Ch] [ebp-Ch]v2 = *(_DWORD *)(*(_DWORD *)(a1 + 4) + 184);if ( v2 == dword_40ADA8 + 6 ){scanf("%20s", v1);if ( !sub_401547(v1, dword_40AD98) )puts(Buffer);}ExitProcess(0);
}

接着把dword_40AD98dump出来xor0x2就行了,得flag为flag{r0b0RUlez!_w3lld0ne}

经验:

  1. 莫名其妙的代码往往是动调.
  2. 变量作为函数说明是函数地址.
  3. GetModuleHandleAGetProcAddress作为好兄弟出现要高度注意
  4. kernel32.dll模块库的AddVectoredExceptionHandler为异常处理函数

BabyXor

开局smc,或者可以叫做加壳,反正去壳,dump出来(其实也可以直接动调)

然后得到

int __cdecl main_0(int argc, const char **argv, const char **envp)
{size_t v3; // eaxint v5; // [esp+50h] [ebp-1Ch]void *v6; // [esp+54h] [ebp-18h]const char *Src; // [esp+58h] [ebp-14h]int v8; // [esp+5Ch] [ebp-10h]sub_4010B4((int)&unk_4395F0, "世界上最简单的Xor");sub_40107D(sub_40102D);if ( --File._cnt < 0 )_filbuf(&File);else++File._ptr;v8 = sub_40108C(&unk_435DC0, 56);Src = (const char *)sub_401041((int)&unk_435DC0, (int)&dword_435DF8, 0x38u);v6 = malloc(0x64u);v3 = strlen(Src);memcpy(v6, Src, v3);v5 = sub_4010C3(&unk_435DC0, Src, &dword_435E30, 56);sub_40101E(v8, Src, v5);return 0;
}

一点符号都没有,丑死了,所幸只有这么一段

先注意看这个:

if ( --File._cnt < 0 )_filbuf(&File);else++File._ptr;

其实这个好像就是fgec()的宏展开,反正通过动调可以得知是输入.

但是这题更输入无关系,在动调中,可以从v3和Src获得一段flag碎片(v3我估计是eax作为返回值导致的,实际是v8)

这里我很傻逼,不理解为什么只有Src有,最后撑不住去看wp了.

发现三个都是flag的一部分v8 Src v5,其实我知道,看代码逻辑完全可以看出,但是我点击v8和v5没显示.后面研究了一下,发现ida是这样的,只有你明确告诉它这是char型,它才会显示内存中被指向的东西,而你直接点进去,显示的是他本身的值,也就是地址

经验:

同上,就是明白了ida的显示问题.

Windows_Reverse1

先脱壳,是upx.

int __cdecl main(int argc, const char **argv, const char **envp)
{char v4[1024]; // [esp+4h] [ebp-804h] BYREFchar v5[1024]; // [esp+404h] [ebp-404h] BYREFmemset(v5, 0, sizeof(v5));memset(v4, 0, sizeof(v4));printf("please input code:");scanf("%s", v5);sub_C21000(v5);if ( !strcmp(v4, "DDCTF{reverseME}") )printf("You've got it!!%s\n", v4);elseprintf("Try again later.\n");return 0;
}

sub_C21000(v5);:

unsigned int __cdecl sub_C21000(const char *a1)
{_BYTE *v1; // ecxunsigned int v2; // ediunsigned int result; // eaxconst char *v4; // ebxv2 = 0;result = strlen(a1);if ( result ){v4 = (const char *)(a1 - v1);do{*v1 = byte_C22FF8[(char)v1[(_DWORD)v4]];++v2;++v1;result = strlen(a1);}while ( v2 < result );}return result;
}

可以发现这里利用地址偏移值取值,长得很奇怪.

然后那个byte_C22FF8是换表ascii码表,根据偏移值替换即可.

经验:

要熟悉偏移值,一开始还以为是ida出错了,动调了一下发现是偏移值

76号

无脱壳

有个花指令去花

有个check函数是最关键的(程序就是比对),而它长这样:

_BOOL4 __cdecl sub_8048580(int a1, int a2)
{char v3; // al_BOOL4 result; // eaxchar v5[128]; // [esp+Ch] [ebp-A0h] BYREFunsigned int v6; // [esp+8Ch] [ebp-20h]v6 = __readgsdword(0x14u);while ( 1 ){memset(v5, 0, sizeof(v5));v3 = *(_BYTE *)(a1 + a2);v5[(v3 + 64) % 128] = 1;switch ( v3 ){case '\n':return a2 == 13 && v5[74] != 0;case '0':if ( a2 || !v5[112] )return 0;a2 = 1;continue;case '1':if ( a2 == 14 && v5[113] )goto LABEL_12;return 0;case '2':if ( a2 == 20 && v5[114] )goto LABEL_15;return 0;case '3':if ( a2 != 89 || !v5[115] )return 0;a2 = 90;continue;case '4':if ( a2 != 15 || !v5[116] )return 0;a2 = 16;continue;case '5':if ( a2 != 14 || !v5[117] )return 0;
LABEL_12:a2 = 15;continue;case '6':if ( a2 != 12 || !v5[118] )return 0;a2 = 13;continue;case '7':if ( a2 != 5 || !v5[119] )return 0;a2 = 6;continue;case '8':result = 0;if ( v5[121] )return a2 == 33 || a2 == 2;return result;case '9':if ( a2 != 1 || !v5[121] )return 0;a2 = 2;continue;case 'a':if ( a2 != 35 || !v5[33] )return 0;a2 = 36;continue;case 'b':if ( a2 != 11 || !v5[34] )return 0;a2 = 12;continue;case 'c':if ( a2 != 32 || !v5[33] )return 0;a2 = 33;continue;case 'd':if ( a2 != 3 || !v5[36] )return 0;a2 = 4;continue;case 'e':if ( a2 != 7 || !v5[37] )return 0;a2 = 8;continue;case 'f':if ( !v5[38] || a2 != 8 && a2 != 4 )return 0;goto LABEL_53;case 'g':return a2 == 12 && v5[52] != 0;case 'h':if ( a2 != 13 || !v5[39] )return 0;a2 = 14;continue;case 'i':if ( a2 != 9 || !v5[41] )return 0;a2 = 10;continue;case 'j':if ( a2 != 10 || !v5[42] )return 0;a2 = 11;continue;case 'k':return a2 == 12 && v5[43] != 0;case 'l':if ( a2 != 19 || !v5[44] )return 0;a2 = 20;continue;case 'm':if ( a2 != 17 || !v5[45] )return 0;a2 = 18;continue;case 'n':return a2 == 18 && v5[45] != 0;case 'o':if ( !v5[46] || a2 != 6 && a2 != 28 )return 0;
LABEL_53:++a2;continue;case 'p':if ( a2 != 30 || !v5[48] )return 0;a2 = 31;break;case 'q':if ( a2 != 29 || !v5[49] )return 0;a2 = 30;break;case 'r':if ( a2 != 20 || !v5[50] )return 0;
LABEL_15:a2 = 21;break;case 's':if ( a2 != 25 || !v5[51] )return 0;a2 = 26;break;case 't':return a2 == 24 && v5[50] != 0;case 'u':if ( a2 != 26 || !v5[53] )return 0;a2 = 27;break;case 'v':if ( a2 != 2 || !v5[54] )return 0;a2 = 3;break;case 'w':if ( a2 != 6 || !v5[55] )return 0;a2 = 7;break;case 'x':if ( a2 != 22 || !v5[56] )return 0;a2 = 23;break;case 'y':if ( a2 != 23 || !v5[57] )return 0;a2 = 24;break;case 'z':return a2 == 21 && v5[33] != 0;default:return 0;}}
}

我以为是平坦化混淆,d810和default都用了,发现不行,也没看出规律.

后面看wp,发现r一下后这些都是可见字符,其中为了保持这个循环下去,要一直找continue,而a2的赋值也给我顺序了,可解flag.

经验:

别急着搜wp

这道题本身就是一种经验

echo-server

这道题主要是考花指令,让我更深入了解了花指令的一些做法.

就直接贴别的师傅的wp了:攻防世界逆向高手题之echo-server_攻防世界 echo-server-CSDN博客

经验:

去花爆红,看看地址如果在代码段中,说明有可能是数据.

对于相对跳转,比如+1,+4之类,说明有些垃圾数据,比如E9,00,直接nop.也可以先u再c,让ida先识别好.

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/876774.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

线段树总集 1

引入 一个数列,单点修改(加),区间查询(和)。 上述问题有很多种解法,如树状数组、分块、平衡树等,今天的主题是著名的线段树。 正题 (不确保按难度升序排序,自己看着目录调顺序吧) 线段树基本原理 因为需要区间查询,所以我们希望有一些捷径能将部分的数的和提前算好…

央视蛇年春晚Counting Stars中文翻译!

视频链接 : httpe990-5b4b-4262-95d7-7ea2f9425874&modal_id=7464989004501486900&type=general 《Counting Stars》是美国流行摇滚乐队OneRepublic演唱的一首歌曲,由主唱瑞恩泰德创作。这首歌收录于乐队的第三张录音室专辑《Native》中,以其充满活力的旋律和深刻的…

htb Networked walkthrough

nmap扫描只有 22 80 443 端口 443端口访问不了 所以入手点只有80端口了 direarch 扫描网站发现了几个有意思的路径backup 路径下发现了一个压缩tar包下载下来解压看看内容发现是网站源码需要代码审计我审计了半天也没发现什么问题看看wp说是加个gif89a的文件头就可以上传文件 我…

Janus Pro:DeepSeek 开源革新,多模态 AI 的未来

Janus Pro 是 DeepSeek 开发的一个开源多模态人工智能框架,它通过集成视觉和语言处理能力,提供了高性能的多模态任务处理能力。 在线体验: https://deepseek-januspro.com/ 背景 Janus Pro 于2025年1月发布,是一个开源的多模态AI框架,能够同时处理视觉和语言信息。它采用了…

2025-01-29 闲话

2025-01-29 闲话我尽量不在大年初一整尬的。于是选择了集句?? 最近单曲循环了两首粤语歌。红日 AH.. AH... AH 命运就算颠沛流离 命运就算曲折离奇 命运就算恐吓着你 做人没趣味 别流泪 心酸 更不应舍弃 我愿能一生永远陪伴你 命运就算颠沛流离 命运就算曲折离奇 命运就算恐吓…

Python基础7——模块

1.模块基础知识内置模块:Python内部提供的功能如sys模块、os模块第三方模块:开发者写好,但需要下载后安装使用安装方法:pip install package_nameWindows环境下提前把pip.exe路径添加到环境变量中 升级pip工具:python36 -m pip install --upgrade pip 安装完成后,如果导入…

本地部署大模型openwebui(ollama部署的deepseetR1)联网搜索的一种解决方案

加入搜索引擎的api就行,本文描述openwebui如何设置Google的api联网搜索你的大部分问题都可以通过看官方文档解决.jpg https://docs.openwebui.com/tutorials/integrations/web_search/ 我尝试了serxing,但是卡在最后搜索上.... 使用这个方案建议:如果用的是windows端的docke…

标题给自己加场戏

新年快乐各位 懒得写学期总结 不会起标题了 铁人两项 昨晚今早做的,补一下题解 就是让你求一个图有多少个三元组 那么,当一个点到另一个点经过点双时,点双里的任何一点都可以作为中转点 所以缩点 但缩完点点双内部就不好处理了 所以给他建成圆方树 圆方树可以做到把简单无向…

如何在本地搭建deepseek(深度探索)

要求:需要一台windows10以上版本的电脑 1.安装ollama打开网址: https://ollama.com/按你的需求下载相应版的ollma,我这就下一个windows版的,一路自动安装即可。2.修改一下ollama的模型model安装位置,默认是C盘 (最大版本容量是400G,磁盘够用的可以跳过)(1) Ollama的模型…

他们知道崩溃即将到来

他们知道崩溃即将到来 克利夫伯格亿万富翁们聚集在特朗普的就职典礼——那些将在崩溃后住在封闭社区的人们 高盛的首席信息官表示,在未来一年,处于前沿的公司将开始使用AI代理人,就像他们是员工一样——作为团队成员分配任务去完成。 他还指出,随着AI通过拥有AI大脑的机器人…

Cisco NX-OS System Software - ACI 16.1(1f)F - 适用于 ACI 模式下的 Nexus 9000 系列交换机系统软件

Cisco NX-OS System Software - ACI 16.1(1f)F - 适用于 ACI 模式下的 Nexus 9000 系列交换机系统软件Cisco NX-OS System Software - ACI 16.1(1f)F 适用于 ACI 模式下的 Cisco Nexus 9000 系列交换机系统软件 请访问原文链接:https://sysin.org/blog/cisco-aci-16/ 查看最新…