一、[GWCTF 2019] xxor
二、[ACTF ] usualcrypto
三、[GXYCTF 2019] luck_guy
抽空来总结一下这几天做的几道题,因为对大小端序不是很了解总是解不对,唉,认识到了要注意大小端序的重要性。
(大一废物,写的不好还请师傅们指点!)
一、[GWCTF 2019] xxor
主函数就是把我们输入的六个数数变换后的数和sub_400770中的六个数进行比对,相等就对了,所以顺着逻辑推回去。
关键的地方都写注释了,看图哦~
所以先要把变换后的数组解出来,看到有大佬用的z3,我太菜了,不会不会。。。其实三个方程三个未知数,手解也不难(好吧,我承认我还是高中水平呜呜呜。。)
然后把伪代码复制粘贴改一改嗯。。。
(注:dword类型在C++里好像是unsigned long)
#include<iostream>
using namespace std;
unsigned long a1[6] = { -548868226 ,550153460 ,3774025685 ,1548802262 ,2652626477, -2064448480};
unsigned long flag[6] = { };
void sub_400686(unsigned long* a1, unsigned long* a, int a2[4])
{
__int64 result; // rax
unsigned int v3; // [rsp+1Ch] [rbp-24h]
unsigned int v4; // [rsp+20h] [rbp-20h]
unsigned long v5; // [rsp+24h] [rbp-1Ch]
unsigned int i; // [rsp+28h] [rbp-18h]
v3 = *a1;
v4 = *a;
v5 = 1166789954 * 64; //v5 = 0;
for (i = 0; i <= 63; ++i)
{
v4 -= (v3 + v5 + 20) ^ ((v3 << 6) + a2[2]) ^ ((v3 >> 9) + a2[3]) ^ 0x10;
v3 -= (v4 + v5 + 11) ^ ((v4 << 6) + *a2) ^ ((v4 >> 9) + a2[1]) ^ 0x20;
v5 -= 1166789954;
}
*a1 = v3;
*a = v4;
}
int main()
{
unsigned long k, m;
int unk[4] = { 2,2,3,4 };
for (int j = 0; j < 5; j += 2)
{
k = a1[j]; //dword_601078 = *((unsigned long *)&v6 + j);
m = a1[j + 1]; //dword_60107C = *((unsigned long *)&v6 + j + 1);
//a2 = (char**)&unk_601060;
sub_400686(&k, &m, unk); //sub_400686(&dword_601078, &unk_601060);
flag[j] = k; //*((_DWORD*)&v11 + j) = dword_601078;
flag[j + 1] = m; //*((_DWORD*)&v11 + j + 1) = dword_60107C;
}
for (int i = 0; i <= 5; ++i)
{
printf("%c%c%c", *((char*)&flag[i] + 2), *((char*)&flag[i] + 1), *(char*)&flag[i]);
}
return 0;
}
最后就要提一下大小端序的问题了,我一开始用的cout就错了,输出是
很认真地观察它的话(然而我没有),就会发现它每三个一组(共六组),顺序颠倒了,所以要用printf倒着输出。
二、[ACTF 2020] usualCrypto
主函数就是把输入的字符串经过sub_401080中的变换后和byte_40E0E4比对,相等即输入正确。
直接看sub_401080函数,一开始的sub_401000是base64换表,可以动态调试得到表。在call sub_401000处下断点,F7步入,然后一直F7单步走,循环几次后,直到要跳转到retn,就是表已经换完了,进入byte_40E0A0查看得到表。
中间就是base64加密了,最后还有个sub_401030函数,之前遇到过加减32的变换,不难看出来是大小写变换,数字不变。
换表base64的题还是用python方便(用C++会很麻烦!),后来看别的师傅的wp,python居然还自带换大小写的功能!呜呜呜我要学python。。。(脚本如下:
import base64
import string
KK='zMXHz3TIgnxLxJhFAdtZn2fFk3lYCrtPC2l9'.swapcase()
flag=''
string1="ABCDEFQRSTUVWXYPGHIJKLMNOZabcdefghijklmnopqrstuvwxyz0123456789+/"
string2="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
flag=KK.translate(str.maketrans(string1,string2))
flag=base64.b64decode(flag)
print(flag)
emm习惯性用C++的我还是用C++做了一遍(太复杂就不贴脚本了)
三、[GXYCTF 2019] luck_guy
这道题挺友好的嗯
先看patch me,到了跳转的地方改个标志位则跳到get_flag
(不过为什么我要patch它,而不是直接看get_flag呢?想不通。。。
其实看一下函数,只要你输入的lucky num是偶数就行了emmmm
进入get_flag,如注释顺序应该是4-5-1
写脚本,同样要注意大小端序!!
emmm f2的前面好像有个空格,但我加空格的话又不太对,但是它是最后一个啊,那不就是"}"么,我就干脆把它删了。。反推回去的话它是一个del。。。。
#include<iostream>
using namespace std;
#include<cstring>
int main()
{
char f1[20] = "GXY{do_not_";
char f2[8] = "fo`guci";
char f3[8] = "NULLlll";
char v1;
int k = 6;
for (int j = 0; j <= 7; ++j)
{
if (j % 2 == 1)
v1 = f2[j] - 2;
else
v1 = f2[j] - 1;
f3[k] = v1;
k--;
}
f3[7] = '\0';
cout << strcat(f1, f3) << "}";
return 0;
}
昨天还看了一道去年极客大挑战的web,学到了加 Referer头伪造访问地址,和XFF从本地请求。。。唉,最近看了很多wp也认识到了小白跟师傅们的差距,就。。挺绝望的。。。希望我能坚持到成功入门吧