攻防世界逆向高手题之catch-me
继续开启全栈梦想之逆向之旅~
这题是攻防世界逆向高手题的catch-me
.
.
照例下载附件,结果两次都提示是用7z
打开(解压),所以要解压两次才能得到真正文件:
.
.
最后得到的文件是一个64
位的ELF
文件:
.
.
照例运行一下程序查看主要回显信息:
.
.
(这里积累第一个经验)
啥也没输入就直接程序结束
了,回顾一下前面做的不用输入
的类型,那时检查文件中flag
的,而且没有对应文件
就闪退的。
.
.
那么这题也是不用输入的,这种不用输入的程序都是直接利用
程序外部
的一些东西来作为条件
继续执行的,所以我们这次也是要修改程序外
的一些东西,来符合程序的执行。
.
.
照例扔入64
位IDA
中查看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
,那么我们要设置满足条件的ASIS
和CTF
环境变量才能执行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
啊。
首先第一个要注意的是v3
的0xB11924E1
本来应该是小端顺序逆序存储在内存中的,可是这里红框中HIBYTE、BYTE2、BYTE1、BYTE
直接把v3按大端顺序
存储了,这点要特别注意,而且还经过了位与&
处理。
然后就是黄框中在v3数组后拼接
了小端
的getenv("ASIS")
,最后我们直接用Export data
直接导出haystack
原始的32位值进行处理即可。
.
.
.
附上脚本,注意源代码中是[i & 7]
差点看错成[i % 7]
了:
key1=0xFEEBFEEB
key2=0xB11924E1
key3=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:
(这里积累第二个经验)
积累一些函数的利用:
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 所指向的环境字符串,并返回相关的值。
3:
(这里积累第三个经验)
所以在前面v3
是直接生成的,这里能获取程序外部
的只有getenv
函数,那么关键地方就是这里if ( getenv("ASIS") && (*(_DWORD *)getenv("CTF") ^ v3) == 0xFEEBFEEB )
.
v3
动态调试发现值是0xB11924E1
,那么我们要设置满足条件的ASIS
和CTF
环境变量才能执行if
语句,才有可能获取flag
。
.
这里其实很多其它博客都忽略了一点就是getenv("ASIS")
应该是要爆破
出来的,首先附上C语言
运算符的优先级
,从图中可以看出只要前面(*(_DWORD *)getenv("CTF") ^ v3) == 0xFEEBFEEB
满足,那么后面getenv("ASIS")
只要不是0就可以。
.
(注意这里&&
不要和&
位运算搞混了,&&
是逻辑与,&是位与。)
.
4:
(这里积累第四个经验)
所以我们导入linux
的环境变量,这里也补充一些基本知识:(注意:expor
t只能在当前终端中有效,终端关闭就没用了)
(通过printf可以导入十六进制整数类型,值得积累)
export ASIS="$(printf "\x0a\xda\xf2\x4f")" #注意参数是从低位到高位的
export CTF="$(printf "\x0a\xda\xf2\x4f")"
5:
(这里积累第5个经验)
另一种方法就是我们既然知道了getenv("ASIS")
的值,我们也可以直接自己生成flag
啊。
.
首先第一个要注意的是v3
的0xB11924E1
本来应该是小端顺序逆序存储在内存中的,可是这里红框中HIBYTE、BYTE2、BYTE1、BYTE
直接把v3按大端顺序
存储了,这点要特别注意,而且还经过了位与&
处理。
.
然后就是黄框中在v3数组后拼接
了小端
的getenv("ASIS")
,最后我们直接用Export data
直接导出haystack
原始的32位值进行处理即可。
解毕!敬礼!