攻防世界新手练习题_REVERSE(逆向)

  • Comments Off on 攻防世界新手练习题_REVERSE(逆向)
  • 47 views
  • A+
所属分类:CTF专场

攻防世界新手练习题_REVERSE(逆向)

re1

题目描述:菜鸡开始学习逆向工程,首先是最简单的题目

做题实录

双击点开,让我输入flag

攻防世界新手练习题_REVERSE(逆向)

随便输一个:

攻防世界新手练习题_REVERSE(逆向)

看样子是要比较字符串的,放到OD里面看看,找到了比较字符串的地方,下断点

攻防世界新手练习题_REVERSE(逆向)

随便输入什么字符之后继续往下走,发现flag已经进入到了ESP中

攻防世界新手练习题_REVERSE(逆向)

分析总结

这个题非常简单,没什么好说的,其实放到OD里还可以直接搜索字符串,一步到位……

攻防世界新手练习题_REVERSE(逆向)

当然了,还可以用IDA直接看源码

攻防世界新手练习题_REVERSE(逆向)

看到strcmp()函数,输入的是v9,和v5比较,所以数据就应该在v5里面,再看第10行,把xmmword_413E34的值赋给v5,所以双击xmmword_413E34看它的数据。把qword_413E44xmmword_413E34的数据拼起来

攻防世界新手练习题_REVERSE(逆向)

你可以把qword_413E44xmmword_413E34的数据拼起来用python把16进制的数转化成文本然后反向写出flag就可以了。

 

print ('7D4654435455443074656D30633165577B465443545544'.decode('hex'))

 

# 解码结果: }FTCTUD0tem0c1eW{FTCTUD

或者光标点击xmmword的数据,按下a键,

攻防世界新手练习题_REVERSE(逆向)

确认就可以直接把它转化成字符串。(我也是后来才知道的,看来ida还是要好好学)

攻防世界新手练习题_REVERSE(逆向)

game

题目描述:菜鸡最近迷上了玩游戏,但它总是赢不了,你可以帮他获胜吗

做题实录

一个exe文件,打开如下:

攻防世界新手练习题_REVERSE(逆向)

让你玩游戏,赢了就有flag,于是玩三个小时玩通关拿到flag。放到OD里动态调试

一路走到这里让你输入n,估计接下来就是字符串比较了,随便输一个继续调试

攻防世界新手练习题_REVERSE(逆向)

这部分一整段都在判断灯的情况,调试的过程中发现只要判断出灯没有全亮,就会跳转回003EF4FB,没有进入game.003E7AB4,所以猜测是成功了就进入这里,于是进去看看

攻防世界新手练习题_REVERSE(逆向)

进来之后,果不其然,是成功的函数

攻防世界新手练习题_REVERSE(逆向)

接下来就运行这个函数,就可以得到flag

攻防世界新手练习题_REVERSE(逆向)

分析总结

这个题还是比较简单的,没啥好说的。再用IDA来试一下

攻防世界新手练习题_REVERSE(逆向)

进入main_0()函数,看到判断语句,逻辑很简单

攻防世界新手练习题_REVERSE(逆向)

进入sub_457AB4()

攻防世界新手练习题_REVERSE(逆向)

这个程序就疯狂跳转,不知道要干啥

进去之后就是这样

攻防世界新手练习题_REVERSE(逆向)

可以直接写个脚本跑,在这里我选择改程序的逻辑,让它跳过判断直接执行这个函数

攻防世界新手练习题_REVERSE(逆向)

这一部分就是判断语句,只要把cmp edx, 1改成cmp edx edx那么条件就恒为真。

特别注意的是:cmp edx, 1占3个字节而cmp edx edx占两个字节,所以最后一个字节用nop填充。否则会出错

修改后如下:

攻防世界新手练习题_REVERSE(逆向)

保存之后双击运行,随便输入一个n,就可以得出flag

攻防世界新手练习题_REVERSE(逆向)

Hello,CTF

题目描述:菜鸡发现Flag似乎并不一定是明文比较的

做题实录

一个exe,运行结果如下:

攻防世界新手练习题_REVERSE(逆向)

要找序列号,IDA看一下:

攻防世界新手练习题_REVERSE(逆向)

看来flag就是这个绿色的字符串了,看到有字母有数字且字母不超过f,所以16进制解码试一下,得到flag:

CrackMeJustForFun

分析总结

这个题比较简单,我开始是用动态调试做的,都差不多,只要看到这个字符串基本上就可以解决了。

open-source

题目描述:菜鸡学逆向学得头皮发麻,终于它拿到了一段源代码

做题实录

源代码如下:

 

#include <stdio.h>

 

#include <string.h>

   
 

int main(int argc, char *argv[]) {

 

if (argc != 4) {

 

printf("what?\n");

 

exit(1);

 

}

   
 

unsigned int first = atoi(argv[1]);

 

if (first != 0xcafe) {

 

printf("you are wrong, sorry.\n");

 

exit(2);

 

}

   
 

unsigned int second = atoi(argv[2]);

 

if (second % 5 == 3 || second % 17 != 8) {

 

printf("ha, you won't get it!\n");

 

exit(3);

 

}

   
 

if (strcmp("h4cky0u", argv[3])) {

 

printf("so close, dude!\n");

 

exit(4);

 

}

   
 

printf("Brr wrrr grr\n");

   
 

unsigned int hash = first * 31337 + (second % 17) * 11 + strlen(argv[3]) - 1615810207;

   
 

printf("Get your key: ");

 

printf("%x\n", hash);

 

return 0;

 

}

看到就是要输入规定的参数运行就可以了,注意这个参数要在命令行中输入。第一个参数直接跑个脚本:

 

print(str(0xcafe))

 

#51966

第二个参数最小的是25,第三个参数h4cky0u

编译之后cmd运行,得到flag:

攻防世界新手练习题_REVERSE(逆向)

分析总结

分析源码,没啥可说的。

simple-unpack

题目描述:菜鸡拿到了一个被加壳的二进制文件

做题实录

UltraEdit打开看一下,搜索flag:

攻防世界新手练习题_REVERSE(逆向)

去掉中间的乱码,得到flag:

flag{Upx_1s_n0t_a_d3liv3r_c0mp4ny}

分析总结

直接查找确实是歪门邪道,毕竟这题是关于加壳的,所以UE看一下:

攻防世界新手练习题_REVERSE(逆向)

看到这是个upx的壳,那直接用upx脱壳就行了:

攻防世界新手练习题_REVERSE(逆向)

脱完壳查找flag即可:

攻防世界新手练习题_REVERSE(逆向)

logmein

题目描述:菜鸡开始接触一些基本的算法逆向了

做题实录

IDA里看一下:

攻防世界新手练习题_REVERSE(逆向)

第26行就是加密算法,写个解密算法就行了:

 

#include<stdio.h>

 

#include<stdlib.h>

 

#include<string.h>

   
 

void main()

 

{

 

int v6;

 

int v9;

 

long long v7;

 

int i;

   
 

v9 = 0;

 

char * str = ":\"AL_RT^L*.?+6/46";

 

v7 = 28537194573619560LL;

 

v6 = 7;

   
 

for ( i = 0;i < 17; ++i )

 

{

 

printf("%c",*((char*)&v7 + i % v6)^str[i]);

 

}

   
 

}

 

// RC3-2016-XORISGUD

分析总结

这个题就是简单的算法逆向,没啥可说的。

insanity

题目描述:菜鸡觉得前面的题目太难了,来个简单的缓一下

做题实录

IDA打开,查找flag,得到flag:

攻防世界新手练习题_REVERSE(逆向)

分析总结

实际上这个题就直接运行,等上几秒它会随机给你输出一些字符串,我第一次运行就直接得到了flag……

攻防世界新手练习题_REVERSE(逆向)

no-strings-attached

题目描述:菜鸡听说有的程序运行就能拿Flag?

做题实录

这是个32位的elf文件,ubuntu里跑一下,出来一堆不知道是啥的东西。

攻防世界新手练习题_REVERSE(逆向)

IDA打开

攻防世界新手练习题_REVERSE(逆向)

这个authenticate()看着很可疑,进去看看:

攻防世界新手练习题_REVERSE(逆向)

看到一个decrypt(...),估计就是它了,进去看看

攻防世界新手练习题_REVERSE(逆向)

看样子是一个解密函数,在decrypt(...)下断点进行动态 调试,进入while循环Hex View跟踪EAX(因为函数返回值就存在EAX里),可以看到flag正在被解密出来,继续往下走

攻防世界新手练习题_REVERSE(逆向)

解密完成,得出flag,去掉0x00就是最终的flag,由于题目来源9447CTF,所以没有前面的1。

攻防世界新手练习题_REVERSE(逆向)

分析总结

我看了一下,基本上都差不多,不过很多都是用gdb调试的,没用过gdb,正好趁这个机会学习一下,写一下gdb调试的方法。

进入gdb后输入 file no-strings-attached 开始调试程序

然后在decrypt()下断点,用命令 break decrypt

按n是单步步过,s是单步步进,啥也不输直接按回车默认执行上一条指令

单步执行到这里发现EAX里面存了9,是flag的开头

攻防世界新手练习题_REVERSE(逆向)

记下此时EAX的位置0x804cff0,输入 finish 让程序执行完当前的函数并返回

攻防世界新手练习题_REVERSE(逆向)

查看EAX的内容,输入命令 x/100u $eax (该命令具体使用方式参见GDB下查看内存命令(x命令)

攻防世界新手练习题_REVERSE(逆向)

写个脚本跑出来就行了

 

s=[57,52,52,55,123,121,111,117,95,97,114,101,95,97,110,95,

 

105,110,116,101,114,110,97,116,105,111,110,97,108,95,109,121,

 

115,116,101,114,121,125]

 

flag=''

 

for i in range(len(s)):

 

flag += chr(s[i])

   
 

print (flag)

   
 

#得出结果:9447{you_are_an_international_mystery}

getit

题目描述:菜鸡发现这个程序偷偷摸摸在自己的机器上搞事情,它决定一探究竟

做题实录

这是个elf文件,在ubuntu里跑了一下发现没反应,放到IDA里看一下

攻防世界新手练习题_REVERSE(逆向)

看样子估计是个解密flag的,看了看数据段发现了t是flag(IDA里面按a把ASCII码变成字符串),但是内容不知道

攻防世界新手练习题_REVERSE(逆向)

攻防世界新手练习题_REVERSE(逆向)

我猜while循环应该就是解密的,于是动态调试一下。

攻防世界新手练习题_REVERSE(逆向)

可以看到在循环的过程中下面flag就已经出现了,继续调试得出flag

攻防世界新手练习题_REVERSE(逆向)

分析总结

这个题其实也可以不用动态调试,因为while循环里转换算法都写好了,自己按照源码写个脚本跑就行了。

 

s = 'c61b68366edeb7bdce3c6820314b7498'

 

flag = ''

 

for i in range(len(s)):

 

if i & 1:

 

t = 1

 

else:

 

t = -1

 

flag += chr(ord(s[i]) + t)

 

print (flag)

   
 

#得出结果: b70c59275fcfa8aebf2d5911223c6589

python-trade

题目描述:菜鸡和菜猫进行了一场Py交易

做题实录

下下来是pyc文件,放到ubuntu里面,用uncompyle反编译(下载过程也踩了很多坑……)并保存到tes.py

uncompyle6 Py.pyc > tes.py

得到源码:

 

# uncompyle6 version 3.3.5

 

# Python bytecode 2.7 (62211)

 

# Decompiled from: Python 2.7.15+ (default, Nov 27 2018, 23:36:35)

 

# [GCC 7.3.0]

 

# Embedded file name: 1.py

 

# Compiled at: 2017-06-02 19:20:43

 

import base64

   
 

def encode(message):

 

s = ''

 

for i in message:

 

x = ord(i) ^ 32

 

x = x + 16

 

s += chr(x)

   
 

return base64.b64encode(s)

   
   
 

correct = 'XlNkVmtUI1MgXWBZXCFeKY+AaXNt'

 

flag = ''

 

print 'Input flag:'

 

flag = raw_input()

 

if encode(flag) == correct:

 

print 'correct'

 

else:

 

print 'wrong'

 

# okay decompiling Py.pyc

是一个加密的程序,那按照它的步骤解密就行了,是一个算法逆向的题。

解密代码如下:

 

import base64

   
 

def decode(message):

 

message = base64.b64decode(message)

 

s = ''

 

for i in message:

 

x = ord(i)-16

 

x = x ^ 32

 

s += chr(x)

   
 

return s

   
 

message = 'XlNkVmtUI1MgXWBZXCFeKY+AaXNt'

 

print (decode(message))

   
 

#得出结果: nctf{d3c0mpil1n9_PyC}

分析总结

这题没啥好说的,就是算法逆向。但是安装使用uncompyle遇到点问题,也记下来吧。

pip install uncompyle

然后使用的时候需要输compyle6,我在输了之后一直提示我“command not found”,后来发现需要执行这两条命令安装环境变量

 

export PATH=PATH

 

PATH=PATH

csaw2013reversing2

题目描述:听说运行就能拿到Flag,不过菜鸡运行的结果不知道为什么是乱码

做题实录

拿到的是个exe文件,双击运行结果如图:

攻防世界新手练习题_REVERSE(逆向)

正如描述所说,是一堆乱码,放到OD里看一下。

发现这个位置就是弹出flag的位置。

攻防世界新手练习题_REVERSE(逆向)

在这儿设个断点,然后进去仔细看。

进来之后看这个函数,发现有两个MessageBox函数,觉得有蹊跷,于是在00B01094处取消跳转,让它往下走看看有什么反应。

攻防世界新手练习题_REVERSE(逆向)

在走的时候把int3用nop填充,00B010A3处的jmp跳转也用nop填充

走到第一个MessageBox,弹出了一个flag,但是什么也没有

攻防世界新手练习题_REVERSE(逆向)

于是点击忽略继续往下走,又遇到了jmp跳转,同样nop填充

走到这flag已经加载进内存了。

攻防世界新手练习题_REVERSE(逆向)

分析总结

方法一:直接修改程序逻辑

参考【XCTF 攻防世界】 Reverse —— csaw2013reversing2

由于是个32位的PE文件(linux下用file命令查看),所以用ida pro打开,F5反编译,生成类C语言的伪代码如下:

攻防世界新手练习题_REVERSE(逆向)

lpMem就是flag的内容。看第10行if语句,如果sub_40102A()IsDebuggerPresent()返回值为真则执行__debugbreak()调试断点函数、子函数sub_401000(...)和退出进程函数ExitProcess(...)函数,否则直接执行MessageBoxA(...)函数弹出flag框。

打开sub_40102A()函数看一下:

攻防世界新手练习题_REVERSE(逆向)

发现返回值恒等于零,那就是说只有在调试状态下才会执行if里面的语句。由于直接双击运行没有在调试环境下,弹出乱码的flag,所以可以肯定if里面的语句是关键点,应该包含解密flag的函数。

打开sub_401000(...)看一下:

攻防世界新手练习题_REVERSE(逆向)

看样子是个解密函数,那应该就是它了。那么思路就很清晰了,我们要让程序跳过if判断,直接执行sub_401000(...)函数,然后再跳过ExitProcess(...)函数执行MessageBoxA(...)函数弹出解密后的flag框。

既然思路已经清晰那么就开始修改程序吧。

这是原本的逻辑:

攻防世界新手练习题_REVERSE(逆向)

使用IDA修改指令的方法是将光标放在要修改的指令上,依次点击Edit -> Patch program -> Assemble,弹出指令修改框进行修改。

修改之后逻辑如下:

攻防世界新手练习题_REVERSE(逆向)

红色标注的就是修改过的地方。修改完成后要保存到文件,依次点击 Edit -> Patch program -> Apply patches to input file…,弹出设置框,选择待打补丁程序进行修改。

最后双击运行修改后的程序,直接弹出已解密的flag框。

攻防世界新手练习题_REVERSE(逆向)

方法二:DLL注入

参考攻防世界 RE csaw2013reversing2

maze

题目描述:菜鸡想要走出菜狗设计的迷宫

做题实录

打开IDA看了半天源码,不知道和迷宫有啥关系,以前没做过这种题,还以为是代码不停跳转什么的,还是最后看了wp才明白,真的是个迷宫(吐血)。还是要做题,提高自己的姿势水平,不然就太naive了。

分析总结

这是个64位的elf文件,放IDA里看一下main函数

攻防世界新手练习题_REVERSE(逆向)

(请无视我刚开始看的时候做的注释)首先看第13行,判断输入的字符串,从这里可以看出要求输入的flag长度为24,且以 'nctf{' 开头,以 '}' 结尾(最后的 '}' 本来是ASCII码,在IDA里把光标选择ASCII码按R键就可以把ASCII码变成字符了)。

由于是迷宫,一般是二维的,所以应该有一个记录坐标的变量,看到v9,在判断中有一个&v9(&v9)+1(也就是v9跟着的的下一个字节的地址),那么可以猜想v9就是一个记录位置坐标信息的二维数组。那么while循环就是在判断输入的字符来改变坐标信息,也就是用户输入字符来走迷宫。

正常来说,v9和v9+1对应着迷宫的行和列(别问我为啥不是列和行,我觉得正常讲话就是行在前,所以自然而然想到行和列。就算不对那到时候再改吗,反正就两种情况。而且下面的分析可以确定就是对应的行和列)。

既然是走迷宫,当然就得判断走没走到终点,看到了第72行的“Congratulations!”,那看一下它前面第70行的判断,判断坐标所在,如果是“#”,就到终点了,说明“#”号就代表终点。而且看一下asc_601060

攻防世界新手练习题_REVERSE(逆向)

有个“#”,看来这应该就是迷宫的地图了。我们的目标就是要走到“#”处。再回过头来看8*v9+SHIDWORD(V9),既然是坐标,说明v9就代表行,而v9+1代表列,而且可以知道迷宫的地图应该是8个字符一行的(因为行增加一,数就增加8)。

至于这个LABLE_15,每走一步都要进入这里,应该就是判断有没有越界什么的函数。

现在基本上就已经理清楚了这个迷宫,只要知道怎么走就行了。while循环里的函数如下:

 

//因为是&v9+1,所以是判断列,也就是左右走

 

bool __fastcall sub_400650(_DWORD *a1)//(_DWORD *)&v9 + 1

 

{

 

//为'O'

 

int v1; // eax

   
 

v1 = (*a1)--; //往左走

 

return v1 > 0;

 

}

   
 

bool __fastcall sub_400660(int *a1)//(int *)&v9 + 1

 

{

 

//为'o'

 

int v1; // eax

   
 

v1 = *a1 + 1; //往右走

 

*a1 = v1;

 

return v1 < 8;

 

}

 

//上下走

 

bool __fastcall sub_400670(_DWORD *a1)//&v9

 

{

 

//为'.'

 

int v1; // eax

   
 

v1 = (*a1)--; //往上走

 

return v1 > 0;

 

}

   
 

bool __fastcall sub_400680(int *a1)//(int *)&v9

 

{

 

//为'0'

 

int v1; // eax

   
 

v1 = *a1 + 1; //往下走

 

*a1 = v1;

 

return v1 < 8;

 

}

总结一下:“.”往上走、“0”往下走、“O”往左走、“o”往右走

拿个脚本把地图写出来(python是真的好用)

 

map = ' ******* * **** * **** * *** *# *** *** *** *********'

 

for i in range(0, len(map), 8):

 

print (map[i: i + 8])

   
 

#得出结果:

 

'''

 

******

 

* * *

 

*** * **

 

** * **

 

* *# *

 

** *** *

 

** *

 

********

 

'''

要求步长为18,从左上角开始走,走到“#”的位置,走就行了,最后结果为

nctf{o0oo00O000oooo..OO}