Buuctf 逆向wp
- easyre
下载附件,打开ida,shift+f12得到flag
- 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}
- 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。
flag{hack1ng_fo1_fun}
- 内涵的软件
同第一题,ida打开就能搜到flag。
- 新年快乐
例行检查
有壳,先用upx shell脱壳
然后再放入ida
跟进
比较的是输入的变量和v4相不相等,相等即为flag。
V4是“HappyNewYear!”所以
Flag{ HappyNewYear!}
- Xor
下载附件,查壳(发现不是exe文件,检测不到壳所以换了die去查了一下,依然没有壳)
![](/i/l/?n=22&i=blog/2908407/202210/2908407-20221019195330656-1871880014.png)
拖入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
- Helloword
下载下来查壳,发现是个apk文件,这个就要用到jadx了
也是很轻松的在主菜单找到flag
- 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
- 不一样的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}
- 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}
- 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_!}
- 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}
- [BJDCTF2020]JustRE
例行检查,32位无壳,拖进ida,shift+f12可以看见一个类似于flag的东西
跟进查看源码
看见一个输出语法,而且是把bjd括号里的所有东西解出来了,直接试flag{1999902069a45792d233ac}
成功(这么简单?我怀疑人生)
- 刮开有奖
这个属于是看了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}
- 简单注册器
挺简单一个题,看源码也能轻松看出来。
例行检查,apk文件无壳,放入jadx,找到关键代码
可以看出x是flag,但是经过了一些修改,我们可以通过脚本修改,也可以手动修改,然后后面那个循环是反转字符串,丢尽python里切片就行
Flag{59acc538825054c7de4b26440c0999dd}
- [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="")
- [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)
- 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的时候发现这是一个凯撒加密的算法(密码学一生之敌)
- 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}
既然下都下了,那就好好试试。
- [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}
- 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
- [FlareOn4]login
还准备写脚本结果发现不用。
下载附件,发现是一个网站,f12
直接在if前面加上alert(rotFlag)即可
- [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))
- [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}
- [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}
- [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}
注:部分函数意义:
- [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}
- [WUSTCTF2020]level2
例行检查,有upx加壳
进行去壳处理,拖进upxshell每个版本都脱一次,然后拖入ida得到flag
- [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,查找字符串
![](/i/l/?n=22&i=blog/2908407/202210/2908407-20221019195331593-512390442.png)
有点多,筛选一下
![](/i/l/?n=22&i=blog/2908407/202210/2908407-20221019195331352-291180714.png)
![](/i/l/?n=22&i=blog/2908407/202210/2908407-20221019195331625-356169212.png)
找到
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}
标签:__,逆向,buuctf,return,sub,int,chr,flag,wp From: https://www.cnblogs.com/fuxuqiannian/p/16807544.html