Buuctf 逆向wp

  1. easyre

下载附件,打开ida,shift+f12得到flag

  1. reverse1

下载附件,打开ida,shift+f12,有一个可疑字符串

点进去跟进,f5查看代码

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);

}

Strncmp有三个参数

也就是说,在此需要比较str1和str2的前面v3这个数字的字符,如果str1和str2相等,循环成功进入,而str1是我们要输入的字符串,所以这个时候看str2

发现是hello world,但是提交不正确,再看看有哪里遗漏的没有

发现这一处if有问题,str2有可能在此处被修改,而这里的111和48很明显就是ascall码里面的0和o。

所以这里差的一环就是把原来hallo world的两个o换成0即可

flag{hell0_w0rld}

  1. reverse2

老套路找到这个地方

跟进得到代码

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) == 105 || *(&flag + i) == 114 )

*(&flag + i) = 49;

}

}

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;

}

逆向就要逆着看,先看最后的if判断,比较s2和flag,如果我们输入的flag和s2这个变量相等就提示是正确的,而前面有个对flag进行for循环的,应该也是对其进行改变,ascall码中105和114分别对应i和r,而49对应数字1。之前在字符那里看见过一个疑似flag的字符串hacking_for_fun,那应该是改变里面的i和r转换成1。

得到了hack1ng_fo1_fun

flag{hack1ng_fo1_fun}

  1. 内涵的软件

同第一题,ida打开就能搜到flag。

  1. 新年快乐

例行检查

有壳,先用upx shell脱壳

然后再放入ida

跟进

比较的是输入的变量和v4相不相等,相等即为flag。

V4是“HappyNewYear!”所以

Flag{ HappyNewYear!}

  1. Xor

下载附件,查壳(发现不是exe文件,检测不到壳所以换了die去查了一下,依然没有壳)

拖入ida,f5查看伪代码

我们输入的flag是v7,长度固定为33,而且在if检测之前会把flag进行异或处理(异或符号为^)就是把字符串每一项和它前一项进行异或,再if判断,而if判断里面很明显有一个global是我们需要找的,跟进

得到这些字符,整理出来为:

'f',0xA ,'k',0xC,'w','&','O','.','@',0x11,'x',0xD,'Z',';','U',0x11,'p',0x19,'F',0x1F,'v','"','M','#','D',0xE,'g',0x6,'h',0xF,'G','2','O'

然后对其进行再次异或(需要用的知识点:两次xor等于没有xor)

脚本如下:

key = ['f',0xA ,'k',0xC,'w','&','O','.','@',0x11,'x',0xD,'Z',';','U',0x11,'p',0x19,'F',0x1F,'v','"','M','#','D',0xE,'g',0x6,'h',0xF,'G','2','O']

flag = "f"

x = 0

for i in range(1,len(key)):
if isinstance(key[i], str):
if isinstance(key[i-1], str): x = ord(key[i])^ord(key[i-1])
else: x = ord(key[i])^key[i-1]

else:
if isinstance(key[i-1], str): x = key[i]^ord(key[i-1])
else: x = key[i]^key[i-1]
flag += chr(x)
print(flag)

cmd命令解的flag

挺中二一flag

  1. Helloword

下载下来查壳,发现是个apk文件,这个就要用到jadx了

也是很轻松的在主菜单找到flag

  1. Reverse3

例行检查,32位+无壳+exe文件,放进ida,f12查看字符串

跟进,f5查看伪代码

可以看见中间有一个函数,改写了str的值,跟进sub_4110be这个函数

想了大半天啊。没看出来是干嘛的,上网搜了一下,是base64的加密算法(密码学菜鸡实锤),偏移了一位,得用脚本给它逆推一下。

import base64

str="e3nifIH9b_C@n@dH"

flag=""

for i in range(len(str)):

flag+=chr(ord(str[i])-i)

print(base64.b64decode(flag))

得到flag

  1. 不一样的flag

不一样,真的不一样,这东西就很魔性,估计要多刷上几次这个题了

首先例行检查

32位,没有壳,直接拖入ida

Shift+f12查看字符串

在这里其实有两个奇怪的字符串,但是我只看见了flag

跟进flag这个字符串

找到了main函数,f5查看伪源代码

一开始我以为是弄了一个陷阱,实际上的flag和v3没关系那样子,结果v5和v4这样的变量也没找到,后面看见了the order,order的意思是顺序,那这个题的flag是输入的顺序!

后面看了看别人的wp,才发现忘了另外一个长的非常奇怪的字符串“*11110100001010000101111#”,再加上最后的for循环那里,49ascall编码代表的是1,35代表的是#。

exit(1)表示异常退出.这个1是返回给操作系统的不过在DOS好像不需要这个返回值
exit(0)表示正常退出

那这就已经真相大白了,就是把从*开始的字符串分成5行5列(感觉这里挺牵强的,题目应该给点提示之类的)

然后从*开始不碰1走到#这里,所走的顺序就是flag

flag{222441144222}

  1. SimpleRev

例行检查,没有壳,拖进ida,看见了

跟进

到了一个叫decry的函数里面,然后shift+f12(代码有点多,不展示全部了)

这里有一个比较,显然和flag有关,移上去查看相关变量。

str2是由key和其他一些变量修改来的,而其中一个变量v1需要我们输入。

再看text

现在先找和text有关的变量

Key3跟进

然后跟进v9

这种低地址放低字节高地址放高字节的排序方式叫做小端序,一般用于存储,但是读写一般是大端序读写

所以回到函数体里面,v9

R一下换为字符串

然后因为是小端排序,所以反向一下得到hadow,加上key3的kills,即为killshadow,text值了然。

接下来以此类推,src的值为NDCLS

Key1的值为ADSFK

而key的值需要经过下面两个函数改变而来。

Strcpy():将key1的值赋给key

Strcat():将key的值和src的值拼接,然后交给key

所以经过这两个函数之后,key的值变成了ADSFKNDCLS

然后借鉴了题解的脚本,这个脚本用的是暴力破解

text = "killshadow"
loop = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" #这个暴力破解只能是用大写字母是因为第十一行的if限制在二十六个大写字母之间操作
v2 = 0
v3 = 0
s = ''
key: str = 'ADSFKNDCLS'
v5 = len(key)
flag = ''

for i in range(0, v5):
if 64 < ord(key[i]) <= 90:
s += chr(ord(key[i]) + 32)
else:
s += key[i]

print(s)

for i in range(0, len(text)):
for j in loop:
if ord(text[i]) == (ord(j) - 39 - ord(s[i]) + 97) % 26 + 97:
flag += j

print(flag)

解出来flag为

Flag{KLDQCUDFZO}

  1. Java逆向解密

例行检查,发现是一个java代码,无壳,丢进jadx.gui里

只有两个类,第一个类是做输入输出用的,第二个类才是对输入进行修改的。

首先对输入进行+一个@字符,然后进行异或,最后和keylist里面的值进行比较,全部相等即的话输入的才为flag

那就是对keylist先减去@的值再异或一次就可以得到flag了

Python脚本如下:

loop = [180, 136, 137, 147, 191, 137, 147, 191, 148, 136, 133, 191, 134, 140, 129, 135, 191, 65]
s = len(loop)
flag = ""

for i in range(0, s):
loop[i] = (loop[i] - 64) ^ 32
flag += chr(loop[i])

print(flag)

flag{This_is_the_flag_!}

  1. luck_guy

例行检查,无壳,放进ida

Shift+f12查看字符串

有一个有关flag的字符串,跟进

F5查看源码

关键函数get_flag里的流程是一个for循环包着一个switch case,case1

执行的是flag的输出,而flag的输出又和f1,f2有关

而前面还有两个奇怪的函数

点进main函数,可以看到

也就是我们输入的值会放进patch_me进行操作,打开patch_me

这里a1是一个形参,指的就是刚才在main函数输入的v4值,如果输入的值是偶数,那么就可以进入get_flag函数里。

这里就是整个程序的大致流程

现在我们跟进get_flag里面的f1

得到一个字符串,接着跟进f2,是一个未定义的空变量,那么对于f2的操作在case4和5都有,顺序应该是4,5,1。

脚本如下:

flag = "GXY{do_not_"
f2 = [0x7f, 0x66, 0x6f, 0x60, 0x67, 0x75, 0x63, 0x69][::-1] #此程序用的小端法存储,所以要反转一下
s = ''
for i in range(0, len(f2)):
if i % 2 == 1:
s = chr(int(f2[i]) - 2) #此处求得是程序里f2的值,不是程序里f2+i的值
else:
s = chr(int(f2[i]) - 1)
flag += s
print(flag)

flag{do_not_hate_me}

  1. [BJDCTF2020]JustRE

例行检查,32位无壳,拖进ida,shift+f12可以看见一个类似于flag的东西

跟进查看源码

看见一个输出语法,而且是把bjd括号里的所有东西解出来了,直接试flag{1999902069a45792d233ac}

成功(这么简单?我怀疑人生)

  1. 刮开有奖

这个属于是看了wp还能懵半天的

例行检查,32位无壳,放入ida,查找相关字符。

上面这行表示有base64加密,下面这行应该就是有flag隐藏的函数,跟进查看源码。

INT_PTR __stdcall DialogFunc(HWND hDlg, UINT a2, WPARAM a3, LPARAM a4)

{

const char *v4; // esi

const char *v5; // edi

int v7[2]; // [esp+8h] [ebp-20030h] BYREF

int v8; // [esp+10h] [ebp-20028h]

int v9; // [esp+14h] [ebp-20024h]

int v10; // [esp+18h] [ebp-20020h]

int v11; // [esp+1Ch] [ebp-2001Ch]

int v12; // [esp+20h] [ebp-20018h]

int v13; // [esp+24h] [ebp-20014h]

int v14; // [esp+28h] [ebp-20010h]

int v15; // [esp+2Ch] [ebp-2000Ch]

int v16; // [esp+30h] [ebp-20008h]

CHAR String[65536]; // [esp+34h] [ebp-20004h] BYREF

char v18[65536]; // [esp+10034h] [ebp-10004h] BYREF

if ( a2 == 272 )

return 1;

if ( a2 != 273 ) // a2不等于273

return 0;

if ( (_WORD)a3 == 1001 )

{

memset(String, 0, 0xFFFFu);

GetDlgItemTextA(hDlg, 1000, String, 0xFFFF);

if ( strlen(String) == 8 )

{

v7[0] = 'Z';

v7[1] = 'J';

v8 = 'S';

v9 = 'E';

v10 = 'C';

v11 = 'a';

v12 = 'N';

v13 = 'H';

v14 = '3';

v15 = 'n';

v16 = 'g';

sub_4010F0((int)v7, 0, 10); // v7数组等于[90,74]

memset(v18, 0, 0xFFFFu);

v18[0] = String[5];

v18[2] = String[7];

v18[1] = String[6];

v4 = sub_401000((int)v18, strlen(v18)); // //base64加密

memset(v18, 0, 0xFFFFu);

v18[1] = String[3];

v18[0] = String[2];

v18[2] = String[4];

v5 = sub_401000((int)v18, strlen(v18));

if ( String[0] == v7[0] + 34

&& String[1] == v10 // c

&& 4 * String[2] - 141 == 3 * v8 // a

&& String[3] / 4 == 2 * (v13 / 9) // @

&& !strcmp(v4, "ak1w") // //jMp

&& !strcmp(v5, "V1Ax") )

{

MessageBoxA(hDlg, "U g3t 1T!", "@_@", 0);

}

}

return 0;

}

if ( (_WORD)a3 != 1 && (_WORD)a3 != 2 )

return 0;

EndDialog(hDlg, (unsigned __int16)a3);

return 1;

}

最开始是初始化(memset也是初始化,学到了),然后有一个if语句

这个string猜测是flag,那么flag就有8位。

后面string[2]到string[7]有关的函数是sub_401000

与v4和v5有关,跟进这个函数

发现是刚才的base64加密,于是把v4和v5连起来解密

得到一个字符串,但是这个字符串是v18, string[2]到string[7]对照为WP1jMp

String[0]和string[1]则是和sub_4010F0有关,跟进发现一大堆代码,后面看了大佬的题解才知道这个函数不止操作了传的参数v7,而是用寻址找到了v7到v16这11个数并进行了操作。

这里我们直接把伪代码转化为c代码,用数组寻址的方法解出11个数在函数运行之后的样子

#include <stdio.h>

int sub_4010F0(char* a1, int a2, int a3)

{

int result; // eax

int i; // esi

int v5; // ecx

int v6; // edx

result = a3;

for ( i = a2; i <= a3; a2 = i )

{

v5 = i;

v6 = i[a1];

if ( a2 < result && i < result )

{

do

{

if ( v6 > a1[result])

{

if ( i >= result )

break;

++i;

a1[v5] = a1[result];

if ( i >= result )

break;

while ( a1[i] <= v6 )

{

if ( ++i >= result )

goto LABEL_13;

}

if ( i >= result )

break;

v5 = i;

a1[result] = a1[i];

}

--result;

}

while ( i < result );

}

LABEL_13:

a1[result] = v6 ;

sub_4010F0(a1, a2, i - 1);

result = a3;

++i;

}

return result;

}

int main()

{

char str[] = "ZJSECaNH3ng";

sub_4010F0(str,0,10);

printf("%s", str);

return 0;

}

得到了3CEHJNSZagn

然后得到string[0] = U

string[1] = J

再加上原来解出来的得到flag{UJWP1jMp}

  1. 简单注册器

挺简单一个题,看源码也能轻松看出来。

例行检查,apk文件无壳,放入jadx,找到关键代码

可以看出x是flag,但是经过了一些修改,我们可以通过脚本修改,也可以手动修改,然后后面那个循环是反转字符串,丢尽python里切片就行

Flag{59acc538825054c7de4b26440c0999dd}

  1. [GWCTF 2019]pyre

一个pyc文件,在网上找到了在线逆向网站python反编译 - 在线工具 (tool.lu),反编译出来是这样

#!/usr/bin/env python

# visit https://tool.lu/pyc/ for more information

# Version: Python 2.7

print "Welcome to Re World!"

print "Your input1 is your flag~"

l = len(input1)

for i in range(l):

num = ((input1[i] + i) % 128 + 128) % 128

code += num

for i in range(l - 1):

code[i] = code[i] ^ code[i + 1]

print code

code = [

"\x1f",

"\x12",

"\x1d",

"(",

"0",

"4",

"\x01",

"\x06",

"\x14",

"4",

",",

"\x1b",

"U",

"?",

"o",

"6",

"*",

":",

"\x01",

"D",

";",

"%",

"\x13",

]

上脚本:

code = ['\x1f', '\x12', '\x1d', '(', '0', '4', '\x01', '\x06', '\x14', '4', ',', '\x1b', 'U', '?', 'o', '6', '*', ':',
'\x01', 'D', ';', '%', '\x13']
l = len(code)
for i in range(l - 2, -1, -1):
code[i] = chr(ord(code[i]) ^ ord(code[i + 1]))
for i in range(l):
print(chr((ord(code[i]) - i) % 128), end="")

  1. [ACTF新生赛2020]easyre

例行检查,发现好像有壳

用UPXshell脱一下

脱完之后再回头看

真的无壳了,拖进ida

有一个main函数,查看源代码

上脚本

key = '~}|{zyxwvutsrqponmlkjihgfedcba`_^]\[ZYXWVUTSRQPONMLKJIHGFEDCBA@?>=<;:9876543210/.-,+*)(\'&%$# !"'
encrypt = [42, 70, 39, 34, 78, 44, 34, 40, 73, 63, 43, 64]
flag = ''
x = []
for i in encrypt:
x.append(key.find(chr(i)) + 1)
for i in x:
flag += chr(i)
print(flag)

  1. Findit

一个apk文件,拖进jadx查看

Main菜单里的代码,不算难看,但是有点麻烦,自己写了一个脚本

b = ['p', 'v', 'k', 'q', '{', 'm', '1', '6', '4', '6', '7', '5', '2', '6', '2', '0', '3', '3', 'l', '4', 'm', '4', '9', 'l', 'n', 'p', '7', 'p', '9', 'm', 'n', 'k', '2', '8', 'k', '7', '5', '}']
y = ""
z = ""
for i in range(0, 38):
if (ord(b[i]) < 65 or ord(b[i]) > 90) and (ord(b[i]) < 97 or ord(b[i]) > 122):
y += b[i]
else:
y += chr((ord(b[i]) + 16))
for i in range(0, 38):
if (97 > ord(y[i]) > 90) or ord(y[i]) >= 122:
z += chr(ord(y[i]) - 26)
else:
z += y[i]
print(z)

但是脚本输出的是

flagac164675262033b4c49bdf7f9cda28a75c

一对{}被a和c代替了,所以正确的flag应该是

Flag{ c164675262033b4c49bdf7f9cda28a75}

后面看wp的时候发现这是一个凯撒加密的算法(密码学一生之敌)

  1. rsa

耗时一天,学会了安装一把梭。

下载附件,两个奇奇怪怪的文件,没接触过,无奈看题解,要安装rsactftool。

Kali问题不断,耗时一天安装上了rsactftool,详情看https://blog.csdn.net/qq_43390703/article/details/108500236这篇文章

安装完之后把两个文件复制粘贴到rsatool文件夹下,在当前文件夹终端输入python3 RsaCtfTool.py --publickey pub.key --uncipherfile flag.enc

所以flag为

flag{decrypt_256}

既然下都下了,那就好好试试。

  1. [ACTF新生赛2020]rome

例行检查,

拖进ida,查看字符串

跟进,查看源码

int func()

{

int result; // eax

int v1[4]; // [esp+14h] [ebp-44h]

unsigned __int8 v2; // [esp+24h] [ebp-34h] BYREF

unsigned __int8 v3; // [esp+25h] [ebp-33h]

unsigned __int8 v4; // [esp+26h] [ebp-32h]

unsigned __int8 v5; // [esp+27h] [ebp-31h]

unsigned __int8 v6; // [esp+28h] [ebp-30h]

int v7; // [esp+29h] [ebp-2Fh]

int v8; // [esp+2Dh] [ebp-2Bh]

int v9; // [esp+31h] [ebp-27h]

int v10; // [esp+35h] [ebp-23h]

unsigned __int8 v11; // [esp+39h] [ebp-1Fh]

char v12[29]; // [esp+3Bh] [ebp-1Dh] BYREF

strcpy(v12, "Qsw3sj_lz4_Ujw@l");

printf("Please input:");

scanf("%s", &v2);

result = v2;

if ( v2 == 65 )

{

result = v3;

if ( v3 == 67 )

{

result = v4;

if ( v4 == 84 )

{

result = v5;

if ( v5 == 70 )

{

result = v6;

if ( v6 == 123 )

{

result = v11;

if ( v11 == 125 )

{

v1[0] = v7;

v1[1] = v8;

v1[2] = v9;

v1[3] = v10;

*(_DWORD *)&v12[17] = 0;

while ( *(int *)&v12[17] <= 15 )

{

if ( *((char *)v1 + *(_DWORD *)&v12[17]) > 64 && *((char *)v1 + *(_DWORD *)&v12[17]) <= 90 )

*((_BYTE *)v1 + *(_DWORD *)&v12[17]) = (*((char *)v1 + *(_DWORD *)&v12[17]) - 51) % 26 + 65;

if ( *((char *)v1 + *(_DWORD *)&v12[17]) > 96 && *((char *)v1 + *(_DWORD *)&v12[17]) <= 122 )

*((_BYTE *)v1 + *(_DWORD *)&v12[17]) = (*((char *)v1 + *(_DWORD *)&v12[17]) - 79) % 26 + 97;

++*(_DWORD *)&v12[17];

}

*(_DWORD *)&v12[17] = 0;

while ( *(int *)&v12[17] <= 15 )

{

result = (unsigned __int8)v12[*(_DWORD *)&v12[17]];

if ( *((_BYTE *)v1 + *(_DWORD *)&v12[17]) != (_BYTE)result )

return result;

++*(_DWORD *)&v12[17];

}

return printf("You are correct!");

}

}

}

}

}

}

return result;

}

上脚本

flag = ''

v12 = 'Qsw3sj_lz4_Ujw@l'

for i in range(0, 16):
for j in range(0, 127):
k = j
if 64 < j <= 90:
j = (j - 51) % 26 + 65
if 96 < j <= 122:
j = (j - 79) % 26 + 97

if j == ord(v12[i]):
flag += chr(k)

print(flag)

得到flag{Cae3ar_th4_Gre@t}

  1. CrackRTF

例行检查,无壳拖进ida

F5查看源代码

int __cdecl main_0(int argc, const char **argv, const char **envp)

{

DWORD v3; // eax

DWORD v4; // eax

char Str[260]; // [esp+4Ch] [ebp-310h] BYREF

int v7; // [esp+150h] [ebp-20Ch]

char String1[260]; // [esp+154h] [ebp-208h] BYREF

char Destination[260]; // [esp+258h] [ebp-104h] BYREF

memset(Destination, 0, sizeof(Destination));

memset(String1, 0, sizeof(String1));

v7 = 0;

printf("pls input the first passwd(1): ");

scanf("%s", Destination);

if ( strlen(Destination) != 6 )

{

printf("Must be 6 characters!\n");

ExitProcess(0);

}

v7 = atoi(Destination);

if ( v7 < 100000 )

ExitProcess(0);

strcat(Destination, "@DBApp");

v3 = strlen(Destination);

sub_40100A((BYTE *)Destination, v3, String1);

if ( !_strcmpi(String1, "6E32D0943418C2C33385BC35A1470250DD8923A9") )

{

printf("continue...\n\n");

printf("pls input the first passwd(2): ");

memset(Str, 0, sizeof(Str));

scanf("%s", Str);

if ( strlen(Str) != 6 )

{

printf("Must be 6 characters!\n");

ExitProcess(0);

}

strcat(Str, Destination);

memset(String1, 0, sizeof(String1));

v4 = strlen(Str);

sub_401019((BYTE *)Str, v4, String1);

if ( !_strcmpi("27019e688a4e62a649fd99cadaafdb4e", String1) )

{

if ( !(unsigned __int8)sub_40100F(Str) )

{

printf("Error!!\n");

ExitProcess(0);

}

printf("bye ~~\n");

}

}

return 0;

}

这段代码有两个加密函数,分别加密了两段密码,第一段是

代码中的0x8004是标识符,是sha1的加密算法

所以我们可以用python中的hashlib模块把前六位密码爆破出来(100001-999999)(因为密码必须是六位数)

import hashlib

string='@DBApp'

for i in range(100000,999999):

flag=str(i)+string

x = hashlib.sha1(flag.encode("utf8"))

y = x.hexdigest()

if "6e32d0943418c2c33385bc35a1470250dd8923a9" == y:

print(flag)

break

结果为123321@DBApp
所以我们知道了前六位密码是123321,输入进程序

第二部分我们进入函数看一下,发现标识码是0x8003u  MD5加密

(在这里我看wp没咋看懂,后面找了一个网站解出来)对密文27019e688a4e62a649fd99cadaafdb4e解密,解密出来是~!3a@0123321@DBApp,因为这段密文是和原来第一段密码合在一起加密的,所以除去第一段密码123321和@DBApp,就剩下了~!3a@0,也输入进程序

程序退出来了,我们在文件夹里得到了一个.rtf文件,直接打开即可获得flag

  1. [FlareOn4]login

还准备写脚本结果发现不用。

下载附件,发现是一个网站,f12

直接在if前面加上alert(rotFlag)即可

flag{ClientSideLoginsAreEasy@flare-on.com}

  1. [2019红帽杯]easyRE

很奇怪的一个题,不同于之前做的任何题,他有干扰函数。

例行检查,无壳,拖进ida,f12发现类似于关键函数的标志

跟进,发现一串代码

__int64 sub_4009C6()

{

__int64 result; // rax

int i; // [rsp+Ch] [rbp-114h]

__int64 v2; // [rsp+10h] [rbp-110h]

__int64 v3; // [rsp+18h] [rbp-108h]

__int64 v4; // [rsp+20h] [rbp-100h]

__int64 v5; // [rsp+28h] [rbp-F8h]

__int64 v6; // [rsp+30h] [rbp-F0h]

__int64 v7; // [rsp+38h] [rbp-E8h]

__int64 v8; // [rsp+40h] [rbp-E0h]

__int64 v9; // [rsp+48h] [rbp-D8h]

__int64 v10; // [rsp+50h] [rbp-D0h]

__int64 v11; // [rsp+58h] [rbp-C8h]

char v12[13]; // [rsp+60h] [rbp-C0h] BYREF

char v13[4]; // [rsp+6Dh] [rbp-B3h] BYREF

char v14[19]; // [rsp+71h] [rbp-AFh] BYREF

char v15[32]; // [rsp+90h] [rbp-90h] BYREF

int v16; // [rsp+B0h] [rbp-70h]

char v17; // [rsp+B4h] [rbp-6Ch]

char v18[72]; // [rsp+C0h] [rbp-60h] BYREF

unsigned __int64 v19; // [rsp+108h] [rbp-18h]

v19 = __readfsqword(0x28u);

qmemcpy(v12, "Iodl>Qnb(ocy", 12);

v12[12] = '\x7F';

qmemcpy(v13, "y.i", 3);

v13[3] = '\x7F';

qmemcpy(v14, "d`3w}wek9{iy=~yL@EC", sizeof(v14));// Iodl>Qnb(ocy\x7Fy.i\x7Fd`3w}wek9{iy=~yL@EC

memset(v15, 0, sizeof(v15));

v16 = 0;

v17 = 0;

sub_4406E0(0, v15, 37LL);

v17 = 0;

if ( ((__int64 (__fastcall *)(char *))sub_424BA0)(v15) == 36 )

{

for ( i = 0; i < (unsigned __int64)((__int64 (__fastcall *)(char *))sub_424BA0)(v15); ++i )

{

if ( (unsigned __int8)(v15[i] ^ i) != v12[i] )

{

result = 4294967294LL;

goto LABEL_13;

}

}

sub_410CC0("continue!");

memset(v18, 0, 65);

sub_4406E0(0, v18, 64LL);

v18[39] = 0;

if ( ((__int64 (__fastcall *)(char *))sub_424BA0)(v18) == 39 )

{

v2 = sub_400E44((const __m128i *)v18);

v3 = sub_400E44((const __m128i *)v2);

v4 = sub_400E44((const __m128i *)v3);

v5 = sub_400E44((const __m128i *)v4);

v6 = sub_400E44((const __m128i *)v5);

v7 = sub_400E44((const __m128i *)v6);

v8 = sub_400E44((const __m128i *)v7);

v9 = sub_400E44((const __m128i *)v8);

v10 = sub_400E44((const __m128i *)v9);

v11 = sub_400E44((const __m128i *)v10);

if ( !(unsigned int)sub_400360(v11, off_6CC090) )

{

sub_410CC0("You found me!!!");

sub_410CC0("bye bye~");

}

result = 0LL;

}

else

{

result = 4294967293LL;

}

}

else

{

result = 0xFFFFFFFFLL;

}

LABEL_13:

if ( __readfsqword(0x28u) != v19 )

sub_444020();

return result;

}

很杂乱,经过分析得知有两个关键点,第一个是continue,前面的函数脚本一下:

g = "Iodl>Qnb(ocy\x7Fy.i\x7Fd`3w}wek9{iy=~yL@EC"
flag = ""

for i in range(0, len(g)):
flag += chr(ord(g[i]) ^ i)
print(flag)

得到一串代码:
Info:The first four chars are `flag`

接下来分析下面的代码,随便跟进一个函数if语句里的函数进行查看

发现有一段疑似base64编码的特征,这种函数有10个,就是经过了十次的base64编码,将得到的函数和off_6cc090进行比较是否相等。

而off_6cc090里面的字符串是:

Vm0wd2VHUXhTWGhpUm1SWVYwZDRWVll3Wkc5WFJsbDNXa1pPVlUxV2NIcFhhMk0xV

经过解码十次后,得到一个网站:

https://bbs.pediy.com/thread-254172.htm

里面讲的是社工学,简单理解就是我们被骗了。。。

返回,查看其他的函数,发现在刚才的off_6cc090下面的函数里,有一个函数很可疑

发现此函数的逻辑就是将byte_6CC0A0字符串进行异或,还可以发现if语句中,有判断是否等于‘f’和‘g’的条件,根据已有信息猜测这个字符数组就是‘flag’。

编写脚本,将v2和flag爆破出来。脚本如下

key2=[0x40,0x35,0x20,0x56,0x5D,0x18,0x22,0x45,0x17,0x2F,0x24,0x6E,0x62,0x3C,0x27,0x54,0x48,0x6C,0x24,0x6E,0x72,0x3C,0x32,0x45,0x5B]

key3='flag'

key4=[]

flag=[]

for x in range(4):

key4.append(chr(key2[x] ^ ord(key3[x])))

print(key4)

for i in range(25):

flag.append(chr(key2[i]^ord(key4[i%4])))

print(''.join(flag))

  1. [GUET-CTF2019]re

这个题不难,但是麻烦

打开附件,例行检查,有壳,拖进Upxshell脱壳之后放进ida,很容易发现关键函数:

_BOOL8 __fastcall sub_4009AE(char *a1)

{

if ( 1629056 * *a1 != 166163712 )

return 0LL;

if ( 6771600 * a1[1] != 731332800 )

return 0LL;

if ( 3682944 * a1[2] != 357245568 )

return 0LL;

if ( 10431000 * a1[3] != 1074393000 )

return 0LL;

if ( 3977328 * a1[4] != 489211344 )

return 0LL;

if ( 5138336 * a1[5] != 518971936 )

return 0LL;

if ( 7532250 * a1[7] != 406741500 )

return 0LL;

if ( 5551632 * a1[8] != 294236496 )

return 0LL;

if ( 3409728 * a1[9] != 177305856 )

return 0LL;

if ( 13013670 * a1[10] != 650683500 )

return 0LL;

if ( 6088797 * a1[11] != 298351053 )

return 0LL;

if ( 7884663 * a1[12] != 386348487 )

return 0LL;

if ( 8944053 * a1[13] != 438258597 )

return 0LL;

if ( 5198490 * a1[14] != 249527520 )

return 0LL;

if ( 4544518 * a1[15] != 445362764 )

return 0LL;

if ( 3645600 * a1[17] != 174988800 )

return 0LL;

if ( 10115280 * a1[16] != 981182160 )

return 0LL;

if ( 9667504 * a1[18] != 493042704 )

return 0LL;

if ( 5364450 * a1[19] != 257493600 )

return 0LL;

if ( 13464540 * a1[20] != 767478780 )

return 0LL;

if ( 5488432 * a1[21] != 312840624 )

return 0LL;

if ( 14479500 * a1[22] != 1404511500 )

return 0LL;

if ( 6451830 * a1[23] != 316139670 )

return 0LL;

if ( 6252576 * a1[24] != 619005024 )

return 0LL;

if ( 7763364 * a1[25] != 372641472 )

return 0LL;

if ( 7327320 * a1[26] != 373693320 )

return 0LL;

if ( 8741520 * a1[27] != 498266640 )

return 0LL;

if ( 8871876 * a1[28] != 452465676 )

return 0LL;

if ( 4086720 * a1[29] != 208422720 )

return 0LL;

if ( 9374400 * a1[30] == 515592000 )

return 5759124 * a1[31] == 719890500;

return 0LL;

}

很麻烦,现在忽然发现可以直接上计算器再弄,后悔了

上脚本:

a = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
a[0] = chr(166163712 // 1629056)
a[1] = chr(731332800 // 6771600)
a[2] = chr(357245568 // 3682944)
a[3] = chr(1074393000 // 10431000)
a[4] = chr(489211344 // 3977328)
a[5] = chr(518971936 // 5138336)
a[7] = chr(406741500 // 7532250)
a[8] = chr(294236496 // 5551632)
a[9] = chr(177305856 // 3409728)
a[10] = chr(650683500 // 13013670)
a[11] = chr(298351053 // 6088797)
a[12] = chr(386348487 // 7884663)
a[13] = chr(438258597 // 8944053)
a[14] = chr(249527520 // 5198490)
a[15] = chr(445362764 // 4544518)
a[16] = chr(981182160 // 10115280)
a[17] = chr(174988800 // 3645600)
a[18] = chr(493042704 // 9667504)
a[19] = chr(257493600 // 5364450)
a[20] = chr(767478780 // 13464540)
a[21] = chr(312840624 // 5488432)
a[22] = chr(1404511500 // 14479500)
a[23] = chr(316139670 // 6451830)
a[24] = chr(619005024 // 6252576)
a[25] = chr(372641472 // 7763364)
a[26] = chr(373693320 // 7327320)
a[27] = chr(498266640 // 8741520)
a[28] = chr(452465676 // 8871876)
a[29] = chr(208422720 // 4086720)
a[30] = chr(515592000 // 9374400)
a[31] = chr(719890500 // 5759124)
for i in range(0, len(a)):
print(a[i], end="")

a[6]直接猜的1,对了,然后flag如下:
flag{e165421110ba03099a1c039337}

  1. [WUSTCTF2020]level1

打开附件,例行检查,无壳,拖进ida查看

对flag这个文件进行了修改,然后保存为output这个文件,修改操作是

逆向脚本为:
a = [198,232,816,200,1536,300,6144,984,51200,570,92160,1200,565248,756,1474560,800,6291456,1782,65536000]

for i in range(19):

if ((i+1) & 1):

print(chr(a[i] >> (i+1)),end="")

else:

print (chr(a[i] // (i+1)),end="")

运行脚本,得到flag

flag{d9-dE6-20c}

  1. [SUCTF2019]SignIn

无壳,丢进ida

分析代码,发现有点像rsa,特别是那个65537,很像,然后搜索相关函数__gmpz_powm()

果然,这个函数的运算过程和rsa加密一样,那我们只要反向解密就能找到flag,先用factordb.com这个网站分解大整数N,分解出来p = 282164587459512124844245113950593348271

q = 366669102002966856876605669837014229419

然后用rsatool把D求出来

D = 91646299298871237857836940212608056141193465208586711901499120163393577626813

之后想要用明文解密文的时候,rsatool显示乱码,所以这个时候得学习一下如何写rsa解密脚本。

脚本如下:
import binascii
n = 103461035900816914121390101299049044413950405173712170434161686539878160984549
c = eval('0xad939ff59f6e70bcbfad406f2494993757eee98b91bc244184a377520d06fc35')
d = 91646299298871237857836940212608056141193465208586711901499120163393577626813
m = pow(c, d, n)
print(binascii.unhexlify(hex(m)[2:]))

解出flag为flag{Pwn_@_hundred_years}

注:部分函数意义:

  1. [MRCTF2020]Transform

学会了一个很有意思的东西。

例行检查,无壳,64位,拖进ida,可以看到一段流程比较清晰的代码

看得出来flag的长度为33,然后经过了两轮修改,修改后的值我们知道为byte_40F0E0:67h, 79h, 7Bh, 7Fh, 75h, 2Bh, 3Ch, 52h, 53h, 79h, 57h,5Eh, 5Dh, 42h, 7Bh, 2Dh, 2Ah, 66h, 42h, 7Eh, 4Ch, 57h,79h, 41h, 6Bh, 7Eh, 65h, 3Ch, 5Ch, 45h, 6Fh, 62h, 4Dh

将它和另外一个数组异或,然后用另外一个数组作为索引查找异或后的值,这里注意一件事

dword_40F040:9, 0Ah, 0Fh, 17h, 7, 18h, 0Ch, 6, 1, 10h, 3, 11h, 20h, 1Dh, 0Bh, 1Eh, 1Bh, 16h, 4, 0Dh, 13h, 14h, 15h, 2, 19h, 5, 1Fh, 8, 12h, 1Ah, 1Ch, 0Eh, 8

看上去上面的数据没错,但是有一个dup(0),我也是被这玩意给迷惑了,后面用8怎么也弄不出来,搜了一下,db 8 dup(0)是一个指令,在后面加8个0的,所以最后一个应该是0,上面的数据同理

所以依然要把3fh这个数据删掉(删掉之后依然有33个数据,合理)

之后就是写脚本

t = [103, 121, 123, 127, 117, 43, 60, 82, 83, 121, 87, 94, 93, 66, 123, 45, 42, 102, 66, 126, 76, 87, 121, 65, 107, 126,
101, 60, 92, 69, 111, 98, 77]
g = [9, 10, 15, 23, 7, 24, 12, 6, 1, 16, 3, 17, 32, 29, 11, 30, 27, 22, 4, 13, 19, 20, 21, 2, 25, 5, 31, 8, 18, 26, 28,
14, 0]
m = [0] * 33
flag = ""

for i in range(len(g)):
t[i] ^= g[i]

for i in range(len(g)):
m[g[i]] = chr(t[i])

for i in range(len(g)):
flag += m[i]

print(flag)

有个大佬的题解最后那个for那里用的join函数,我不太了解这个函数就没用,用的遍历。

flag{Tr4nsp0sltiON_Clph3r_1s_3z}

  1. [WUSTCTF2020]level2

例行检查,有upx加壳

进行去壳处理,拖进upxshell每个版本都脱一次,然后拖入ida得到flag

  1. [ACTF新生赛2020]usualCrypt

涉及base64换表处理

例行检查,无壳,拖进ida,查看main函数

有一个关键函数和一个关键循环,byte_40E0E4为zMXHz3TIgnxLxJhFAdtZn2fFk3lYCrtPC2l9

Flag处理后与它比较相等成功

跟进关键函数,有三个处理操作,先对base64进行了换表,然后base64加密,最后进行了大小写互换

那我们就可以先对byte_40E0E4进行大小写互换,然后恢复表顺序进行解密。

脚本找的大佬题解,第一次接触base64的换表操作

import base64

import base64

flag = ''
dict = {}
offset = 10
orgin = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
for i in range(len(orgin)):
dict[orgin[i]] = orgin[i]
for i in range(6, 15): # sub_401000()
dict[orgin[i]], dict[orgin[i + offset]] = dict[orgin[i + offset]], dict[orgin[i]] # 恢复base64密钥表
secret = 'zMXHz3TIgnxLxJhFAdtZn2fFk3lYCrtPC2l9'.swapcase() # sub_401030()
for i in range(len(secret)):
flag += dict[secret[i]]
flag = base64.b64decode(flag)
print(flag)

解出flag为flag{bAse64_h2s_a_Surprise}

33.[MRCTF2020]Xor

打开附件,例行检查,无壳,拖入ida,找到main函数,但是无法反编译,这里跟进call那一段的地址,f5之后再返回main函数,即可

有一个关键循环,只有一个异或,写脚本即可

t = "MSAWB~FXZ:J:`tQJ\"N@ bpdd}8g"
flag = ""
for i in range(0, 26):
flag += chr(ord(t[i]) ^ i)
print(flag)

原来的字串少了一个M,在hex值里能够找到。

flag{@_R3@1ly_E2_R3verse!}

34.[MRCTF2020]hello_world_go

拖进ida,查找字符串

有点多,筛选一下

找到

flag{hello_world_gogogo}

35.[WUSTCTF2020]level3

打开附件,一个pe文件,用ida打开,main函数下反编译

有一个长得和base64编码过差不多的字符串,尝试解码,发现是乱码,考虑一下码表是不是又给换了,查看字串

这个码表看上去没有变过,那应该是中途有函数改变了码表,转过头去看见了一个和main函数紧挨着的一个函数很可疑

跟进查看

果然是一个修改码表的函数,根据这个写出脚本

import base64
t = list("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/")
m = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
key = "d2G0ZjLwHjS7DmOzZAY0X2lzX3CoZV9zdNOydO9vZl9yZXZlcnGlfD=="
for i in range(10):
t[i], t[19-i] = t[19-i], t[i]
t = "".join(t)
t = str.maketrans(t, m)
print(base64.b64decode(key.translate(t)))

得到flag

flag{Base64_is_the_start_of_reverse}