CTF reverse逆向入门题解集合+逆向相关软件安装
Posted hans774882968
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CTF reverse逆向入门题解集合+逆向相关软件安装相关的知识,希望对你有一定的参考价值。
下载安徽理工大学的ctf软件包:传送门。里面包含了不少软件,IDA、androidKiller、jd-gui等。
除此以外,还需要:
- PETools:查看exe基本信息,在GitHub上开源。
- UPX.exe:exe加壳工具,也可以用来去UPX壳(但连变种的UPX壳都没法去~),在GitHub上开源。
- JEB:参考h鶸的文章安装即可😙
- uncompyle6:把pyc转为python。
pip install uncompyle6
- Linux的file命令可以帮助我们分析一个未知文件的基本信息。
buuoj题目链接:https://buuoj.cn/challenges
jarvisoj题目链接:https://www.jarvisoj.com/challenges
南邮CTF:https://cgctf.x1ct34m.com/challenges
文章目录
buu-easyre
把easyre.exe
拖到idaq64.exe
。然后用软件提供的search功能,搜索flag
即可(这个软件不允许你使用ctrl+F)。
aFlagThis_is_a_ db 'flagthis_Is_a_EaSyRe',0 ; DATA XREF: main+31
关闭:关闭时有选项,选择Pack database(Store)
即可,生成idb文件并删除4个数据库文件(id0等)。Don't pack db
选项不生成idb文件(i64)。而Pack database(Deflate)
保留4个数据库文件和idb文件。再次打开时拖拽idb文件进去即可。
main函数
__int64 __fastcall main(__int64 a1, __int64 a2)
int b; // [sp+28h] [bp-8h]@1
int a; // [sp+2Ch] [bp-4h]@1
_main();
scanf(a1, a2, &a, "%d%d", &b);
if ( a == b )
printf(a1, a2, (unsigned int)a, "flagthis_Is_a_EaSyRe");
else
printf(a1, a2, (unsigned int)a, "sorry,you can't get flag");
return 0LL;
buu-reverse1
在虚拟机里用Linux的file命令查看文件类型得:reverse_1.exe: PE32+ executable (console) x86-64, for MS Windows
。所以是64位程序。用PETools查看,得AMD64(K8)也可以验证。
用ida的搜索功能,搜索字符串flag,直接找到关键函数。
另一个做法:shift+F12看到字符串带flag的,点一下,然后点两下data xref,就可以看到那个函数的汇编代码。按F5转为C伪代码。
int sub_1400118C0()
char *v0; // rdi@1
signed __int64 i; // rcx@1
size_t v2; // rax@5
size_t v3; // rax@9
char v5; // [sp+0h] [bp-20h]@1
signed int v6; // [sp+20h] [bp+0h]@4
char Str1; // [sp+48h] [bp+28h]@9
unsigned __int64 v8; // [sp+128h] [bp+108h]@5
unsigned __int64 v9; // [sp+130h] [bp+110h]@4
v0 = &v5;
for ( i = 82i64; i; --i )
*(_DWORD *)v0 = -858993460;
v0 += 4;
v9 = (unsigned __int64)&v6 ^ _security_cookie;
for ( *(&v6 + 1) = 0; ; ++*(&v6 + 1) )
v8 = *(&v6 + 1);
v2 = j_strlen(Str2);
if ( v8 > v2 )
break;
if ( Str2[(signed __int64)*(&v6 + 1)] == 111 )
Str2[(signed __int64)*(&v6 + 1)] = 48;
sub_1400111D1("input the flag:");
sub_14001128F("%20s", &Str1);
v3 = j_strlen(Str2);
if ( !strncmp(&Str1, Str2, v3) )
sub_1400111D1("this is the right flag!\\n");
else
sub_1400111D1("wrong flag\\n");
sub_14001113B(&v5, &unk_140019D00);
return sub_1400112E9((unsigned __int64)&v6 ^ v9);
右键111和48分别换成Char,得'o'
和'0'
。Str2
是"hello_world"
。所以for循环就是把所有的o
变成0
。
最后oj的题干有”注意:得到的 flag 请包上 flag 提交“,所以提交的字符串就是flaghell0_w0rld
buu-reverse2
这题是Linux可执行程序的hello world。
虽然是在64位Linux下运行的,但也能直接拖进idaq64.exe分析。
在strings window看到和flag有关的字符串,定位到main函数。
int __cdecl main(int argc, const char **argv, const char **envp)
int result; // eax@11
__int64 v4; // rdx@13
int stat_loc; // [sp+4h] [bp-3Ch]@9
int i; // [sp+8h] [bp-38h]@2
__pid_t pid; // [sp+Ch] [bp-34h]@1
char s2; // [sp+10h] [bp-30h]@10
__int64 v9; // [sp+28h] [bp-18h]@1
v9 = *MK_FP(__FS__, 40LL);
pid = fork();
if ( pid )
argv = (const char **)&stat_loc;
waitpid(pid, &stat_loc, 0);
else
for ( i = 0; i <= strlen(&flag); ++i )
if ( *(&flag + i) == 'i' || *(&flag + i) == 'r' )
*(&flag + i) = '1';
printf("input the flag:", argv);
__isoc99_scanf(4196628LL, &s2);
if ( !strcmp(&flag, &s2) )
result = puts("this is the right flag!");
else
result = puts("wrong flag!");
v4 = *MK_FP(__FS__, 40LL) ^ v9;
return result;
flag
的ascii是,注意到aHacking_for_fu这个变量虽然没用到(所以strings window查不到),但它和flag的地址是相邻的,所以**&flag就是字符串
hacking_for_fun
**。然后那个循环逻辑很简单,不赘述。答案flaghack1ng_fo1_fun
buu-内涵的软件
这题是32位程序的hello world。
用Linux的file命令得:xx.exe: PE32 executable (console) Intel 80386, for MS Windows
在String window看到了一些和问题有关的信息,比如中文。于是找到了main函数。
int main_0()
int result; // eax@5
char v1; // [sp+Ch] [bp-4Ch]@1
char v2; // [sp+4Ch] [bp-Ch]@4
int v3; // [sp+50h] [bp-8h]@1
int v4; // [sp+54h] [bp-4h]@1
memset(&v1, 0xCCu, 0x4Cu);
v4 = 5;
v3 = (int)"DBAPP49d3c93df25caad81232130f3d2ebfad";
while ( v4 >= 0 )
printf("距离出现答案还有%d秒,请耐心等待!\\n", v4);
sub_40100A();
--v4;
printf("\\n\\n\\n这里本来应该是答案的,但是粗心的程序员忘记把变量写进来了,你要不逆向试试看:(Y/N)\\n");
v2 = 1;
scanf("%c", &v2);
if ( v2 == 'Y' )
printf("OD吾爱破解或者IDA这些逆向软件都挺好的!");
result = sub_40100A();
else if ( v2 == 'N' )
printf("那没办法了,猜是猜不出的.");
result = sub_40100A();
else
printf("输入错误,没有提示.");
result = sub_40100A();
return result;
这tm啥逻辑都没有啊。后来才意识到v3变量就是所求。
buu-新年快乐
这题是加壳程序的hello world。
用PETools查看exe的基本信息。看入口:Section: [UPX1], EP: 0x000014F0
,所以是加了UPX壳的。用UPX解压即可((powershell) .\\upx.exe -d 新年快乐.exe
)。
顺便记录一下PETools的一些用法:
- File Header --> Machine,发现是Intel 386;查看characteristics也可知这是32位程序。
- File Header --> Time/Date的16进制解码得:2016年1月19日16:09:36。但UTC+8才是真实时间。
int __cdecl main(int argc, const char **argv, const char **envp)
int result; // eax@2
char v4; // [sp+12h] [bp-3Ah]@1
__int16 v5; // [sp+20h] [bp-2Ch]@1
__int16 v6; // [sp+22h] [bp-2Ah]@1
__main();
qmemcpy(&v4, "HappyNewYear!", 0xEu);
v5 = 0;
memset(&v6, 0, 0x1Eu);
printf("please input the true flag:");
scanf("%s", &v5);
if ( !strncmp((const char *)&v5, &v4, strlen(&v4)) )
result = puts("this is true flag!");
else
result = puts("wrong!");
return result;
代码逻辑就是,期望输入串v5 == “HappyNewYear”。所以这就是flag。
buu-xor
这题是mac可执行程序的hello world。
用Linux的file命令查看
$ file xor
xor: Mach-O 64-bit x86_64 executable, flags:<NOUNDEFS|DYLDLINK|TWOLEVEL|PIE>
64位程序。
一眼就能看到main函数。
int __cdecl main(int argc, const char **argv, const char **envp)
signed __int64 v3; // rsi@1
__int64 v4; // rax@8
signed int i; // [sp+2Ch] [bp-124h]@2
char v7[264]; // [sp+40h] [bp-110h]@1
__int64 v8; // [sp+148h] [bp-8h]@1
v8 = *(_QWORD *)__stack_chk_guard_ptr[0];
memset(v7, 0, 0x100uLL);
v3 = 256LL;
printf("Input your flag:\\n", 0LL);
get_line(v7, 256LL);
if ( strlen(v7) != 33 )
goto LABEL_13;
for ( i = 1; i < 33; ++i )
v7[i] ^= v7[i - 1];
v3 = (signed __int64)global;
if ( !strncmp(v7, global, 0x21uLL) )
printf("Success", v3);
else
LABEL_13:
printf("Failed", v3);
v4 = *(_QWORD *)__stack_chk_guard_ptr[0];
if ( *(_QWORD *)__stack_chk_guard_ptr[0] == v8 )
LODWORD(v4) = 0;
return v4;
global的值为06FEH,在那个地址找到字符串,并用shift+E来导出数组:
unsigned char ida_chars[] =
102, 10, 107, 12, 119, 38, 79, 46, 64, 17,
120, 13, 90, 59, 85, 17, 112, 25, 70, 31,
118, 34, 77, 35, 68, 14, 103, 6, 104, 15,
71, 50, 79, 0
;
下面的代码利用的是异或的性质:xyy = x,前缀异或和的相邻元素异或即可还原元素。
let a = [102, 10, 107, 12, 119, 38, 79, 46, 64, 17, 120, 13, 90, 59, 85, 17, 112, 25, 70, 31, 118, 34, 77, 35, 68, 14, 103, 6, 104, 15, 71, 50, 79]
let ans = String.fromCharCode(a[0])
for (let i = 1; i < a.length; ++i)
ans += String.fromCharCode(a[i] ^ a[i - 1])
console.log(ans)
buu-helloword-安卓逆向helloworld
这题是安卓逆向的hello world。只要JEB能正常用就能AC了。
package com.example.helloword;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.view.Menu;
import android.view.MenuItem;
public class MainActivity extends ActionBarActivity
@Override // android.support.v7.app.ActionBarActivity
protected void onCreate(Bundle arg5)
super.onCreate(arg5);
this.setContentView(0x7F030018); // layout:activity_main
"flag7631a988259a00816deda84afb29430a".compareTo("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
@Override // android.app.Activity
public boolean onCreateOptionsMenu(Menu arg3)
this.getMenuInflater().inflate(0x7F0C0000, arg3); // menu:main
return 1;
@Override // android.app.Activity
public boolean onOptionsItemSelected(MenuItem arg3)
return arg3.getItemId() == 0x7F05003C ? true : super.onOptionsItemSelected(arg3); // id:action_settings
buu-Java逆向解密
如题名,Java逆向的hello world。Java逆向有开源的jd-gui,下载
反编译得
import java.util.ArrayList;
import java.util.Scanner;
public class Reverse
public static void main(String[] args)
Scanner s = new Scanner(System.in);
System.out.println("Please input the flag");
String str = s.next();
System.out.println("Your input is");
System.out.println(str);
char[] stringArr = str.toCharArray();
Encrypt(stringArr);
public static void Encrypt(char[] arr)
ArrayList<Integer> Resultlist = new ArrayList<>();
for (int i = 0; i < arr.length; i++)
int result = arr[i] + 64 ^ 0x20;
Resultlist.add(Integer.valueOf(result));
int[] KEY =
180, 136, 137, 147, 191, 137, 147, 191, 148, 136,
133, 191, 134, 140, 129, 135, 191, 65 ;
ArrayList<Integer> KEYList = new ArrayList<>();
for (int j = 0; j < KEY.length; j++)
KEYList.add(Integer.valueOf(KEY[j]));
System.out.println("Result:");
if (Resultlist.equals(KEYList))
System.out.println("Congratulations!");
else
System.err.println("Error!");
输入串进行enc操作,等于KEY,所以为了得到congratulations要输入的串就通过enc的逆过程得到。随便写个js即可。
let k [CTF reverse导图] 逆向手概况&解题步骤