buuctf-reverse
1
reverse3
一进去查看伪代码
15-19行 搜索算法常量发现是一个检验Destination字符结果的算法
发现24行v4是做了一个base64加密
于是dbg动调 找到加密完后的字符“e3nifIH9b_C@n@dH”
简单for循环解密再base64就行
#include <stdio.h>
#include <string.h>
signed int v11;
char Destination[108];
int main()
{
const char *v4 = { "e3nifIH9b_C@n@dH" };
strncpy(Destination, v4, 0x28u);
v11 = strlen(Destination);
for (int j = 0; j < v11; ++j)
{
Destination[j] -= j;
}
printf("%s", Destination);
}
SimpleRev
查看文件是elf
用ida64打开
伪代码如下
unsigned __int64 Decry()
{
char v1; // [rsp+Fh] [rbp-51h]
int v2; // [rsp+10h] [rbp-50h]
int v3; // [rsp+14h] [rbp-4Ch]
int i; // [rsp+18h] [rbp-48h]
int v5; // [rsp+1Ch] [rbp-44h]
char src[8]; // [rsp+20h] [rbp-40h] BYREF
__int64 v7; // [rsp+28h] [rbp-38h]
int v8; // [rsp+30h] [rbp-30h]
__int64 v9[2]; // [rsp+40h] [rbp-20h] BYREF
int v10; // [rsp+50h] [rbp-10h]
unsigned __int64 v11; // [rsp+58h] [rbp-8h]
v11 = __readfsqword(0x28u);
*(_QWORD *)src = 0x534C43444ELL;
v7 = 0LL;
v8 = 0;
v9[0] = 0x776F646168LL;
v9[1] = 0LL;
v10 = 0;
text = join(key3, (const char *)v9);
strcpy(key, key1);
strcat(key, src);
v2 = 0;
v3 = 0;
getchar();
v5 = strlen(key);
for ( i = 0; i < v5; ++i )
{
if ( key[v3 % v5] > 64 && key[v3 % v5] <= 90 )
key[i] = key[v3 % v5] + 32;
++v3;
}
printf("Please input your flag:");
while ( 1 )
{
v1 = getchar();
if ( v1 == 10 )
break;
if ( v1 == 32 )
{
++v2;
}
else
{
if ( v1 <= '`' || v1 > 'z' )
{
if ( v1 > '@' && v1 <= 'Z' )
{
str2[v2] = (v1 - 39 - key[v3 % v5] + 97) % 26 + 97;
++v3;
}
}
else
{
str2[v2] = (v1 - 39 - key[v3 % v5] + 97) % 26 + 97;
++v3;
}
if ( !(v3 % v5) )
putchar(32);
++v2;
}
}
if ( !strcmp(text, str2) )
puts("Congratulation!\n");
else
puts("Try again!\n");
return __readfsqword(0x28u) ^ v11;
}
伪代码流程解读(正向): 先是用一个自定义函数join来拼接(key3,v9 ),text用来接收拼接字符串,再用strcat拼接(key1,src),放入key中存储
for循环判断大小写,小写转换成大写
接下来就是接收输入,无论是否判断大小写,输入字符都和key做一个加减和取余26
最后再和text作对比
逆向想法过程:
因为key,和text在其中没有变换字符串,约等于他们是常量,然而要去余的逆运算,所以要放大取模倍数,符合大写条件的再打印出来
最后附上解密脚本:
#include <stdio.h>
#include <string.h>
#include <malloc.h>
#include <stdint.h>
#include <Windows.h>
char v1; // [rsp+Fh] [rbp-51h]
int v2; // [rsp+10h] [rbp-50h]
int v3; // [rsp+14h] [rbp-4Ch]
int i; // [rsp+18h] [rbp-48h]
int v5; // [rsp+1Ch] [rbp-44h]
__int64 src[1]; // [rsp+20h] [rbp-40h] BYREF
__int64 v7; // [rsp+28h] [rbp-38h]
int v8; // [rsp+30h] [rbp-30h]
__int64 v9[2]; // [rsp+40h] [rbp-20h] BYREF
int v10; // [rsp+50h] [rbp-10h]
unsigned __int64 v11; // [rsp+58h] [rbp-8h]
char key3[6] = { "kills" };
char str2[104];
char* __fastcall join(const char* a1, const char* a2)
{
size_t v2; // rbx
size_t v3; // rax
char* dest; // [rsp+18h] [rbp-18h]
v2 = strlen(a1);
v3 = strlen(a2);
dest = (char*)malloc(v2 + v3 + 1);
if (!dest)
exit(1);
strcpy(dest, a1);
strcat(dest, a2);
return dest;
}
int main()
{
src[0] = 0x534C43444ELL;
v9[0] = 0x776F646168LL;
v9[1] = 0LL;
char* test = join(key3, (const char*)v9);
char key1[] = { "ADSFK" };
char key[128];
strcpy(key, key1);
strcat(key, (const char *)src);
v5 = strlen(key);
char tmp;
char flag[10];
for (i = 0; i < v5; ++i)
{
if (key[v3 % v5] > 64 && key[v3 % v5] <= 90)
key[i] = key[v3 % v5] + 32;
++v3;
}
for (i = 0; i < 10; i++)//放大取模倍数
{
v3 = 10;
for (v2 = 0; v2 < 10; v2++)//十个字符
{
tmp = test[v2] - 97 + i * 26 - 97 + key[v3++ % v5] + 39;
if (tmp >= 65 && tmp <= 90)
flag[v2] = tmp;
}
}
printf("%s", flag);
}
这题总结:失误点:1.总想着直接逆,没有第一时间仔细看代码逻辑,导致最后浪费时间很多
2.对于这种求余的逆运算带括号的逆运算总是写错,要细心一点
经验:像这种16进制字符串v9[0] = 0x776F646168LL,用__int64(long long)来存储强行转换const char 既不会损失精度,也不会截断
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!");
}
}
}
很简单的每个字符+64^0x20
逆向过程就是-64^0x20
最后附上解密代码
#include <stdio.h>
#include <string.h>
int main()
{
char KEY []= {
180, 136, 137, 147, 191, 137, 147, 191, 148, 136,
133, 191, 134, 140, 129, 135, 191, 65 };
int len = strlen(KEY);
for (int i = 0; i < len; i++)
{
int result = KEY[i] - 64 ^ 0x20;
printf("%c", result);
}
}
[GXYCTF2019]luck_guy
伪代码如下:
unsigned __int64 get_flag()
{
unsigned int v0; // eax
int i; // [rsp+4h] [rbp-3Ch]
int j; // [rsp+8h] [rbp-38h]
__int64 s; // [rsp+10h] [rbp-30h] BYREF
char v5; // [rsp+18h] [rbp-28h]
unsigned __int64 v6; // [rsp+38h] [rbp-8h]
v6 = __readfsqword(0x28u);
v0 = time(0LL);
srand(v0); //狡猾的骗局
for ( i = 0; i <= 4; ++i )
{
switch ( rand() % 200 )
{
case 1:
puts("OK, it's flag:");
memset(&s, 0, 0x28uLL);
strcat((char *)&s, f1);
strcat((char *)&s, &f2);
printf("%s", (const char *)&s);
break;
case 2:
printf("Solar not like you");
break;
case 3:
printf("Solar want a girlfriend");
break;
case 4:
s = 0x7F666F6067756369LL;
v5 = 0;
strcat(&f2, (const char *)&s);
break;
case 5:
for ( j = 0; j <= 7; ++j )
{
if ( j % 2 == 1 )
*(&f2 + j) -= 2;
else
--*(&f2 + j);
}
break;
default:
puts("emmm,you can't find flag 23333");
break;
}
}
return __readfsqword(0x28u) ^ v6;
}
伪代码流程解读(正向):
先是跳转不同函数给地址赋值字符串
然后给f1和f2依次赋值(其中值得一提的是f1的是明文赋值,f2则要看汇编找到loc_4008CA:这个函数去得到赋值数据)
随机1到5 ,选择1,2,5就是正确的
随后就是很简单的爆破脚本
#include <stdio.h>
#include <Windows.h>
#include <string.h>
unsigned int v0; // eax
int i; // [rsp+4h] [rbp-3Ch]
int j; // [rsp+8h] [rbp-38h]
__int64 s; // [rsp+10h] [rbp-30h] BYREF
char v5; // [rsp+18h] [rbp-28h]
unsigned __int64 v6; // [rsp+38h] [rbp-8h]
char f1[] = { "GXY{do_not_" };
int check;
int main()
{
char f2[256] = { 0x69,0x63,0x75,0x67,0x60,0x6F,0x66,0x7F };
for(int t=0;t<=100;++t){
for (i = 0; i <= 4; ++i)
{
check = rand() % 200;
if(check==1 || check==4 || check==5)
switch (check)
{
case 1:
puts("OK, it's flag:");
memset(&s, 0, 0x28uLL);
strcat((char*)&s, f1);
strcat((char*)&s, f2);
printf("%s", (const char*)&s);
break;
case 2:
printf("Solar not like you");
break;
case 3:
printf("Solar want a girlfriend");
break;
case 4:
s = 0x7F666F6067756369LL;
v5 = 0;
strcat((char *)&f2, (const char*)&s);
break;
case 5:
for (j = 0; j <= 7; ++j)
{
if (j % 2 == 1)
*(f2 + j) -= 2;
else
--* (f2 + j);
}
break;
default:
puts("emmm,you can't find flag 23333");
break;
}
}
}
}
[BJDCTF2020]JustRE
观看程序功能 发现一个模块getflag
盲猜getflag这里要动调 于是打开x32dbg
找到关键字符串 在前面几个关键跳下断点,nop常规操作后
发现flag,输入发现不对,于是打开ida观察
发现简单的把
BJD{199992069a45792d233ac}19999后面加个0就行
得到flag{1999902069a45792d233ac}
[GWCTF 2019]pyre
下载文件观察文件类型是pyc,百度找一个pyc在线反编译
伪代码如下:
#!/usr/bin/env python
# visit https://tool.lu/pyc/ for more information
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']
很简单的加密过程 先取模再和后一位异或
坑点在于其一这个去模要来一手,取模运算规则
运算规则
模运算与基本四则运算有些相似,但是除法例外。其规则如下:
-
(a + b) % p = (a % p + b % p) % p (1)
其二是在于异或要注意伪代码里面的l-1,倒过来得是后面倒数第二位和倒数第三位开始异或解密过程
C语言脚本如下(由于某种特别力量输出flag会出错,暂且不知道原因)
#include <stdio.h>
#include <Windows.h>
#include <string.h>
int main()
{
int code[] = {
'\x1f',
'\x12',
'\x1d',
'(',
'0',
'4',
'\x01',
'\x06',
'\x14',
'4',
',',
'\x1b',
'U',
'?',
'o',
'6',
'*',
':',
'\x01',
'D',
';',
'%',
'\x13' };
char num[29];
int l = 23;
for (int i = l - 2; i > -1; i--)
{
code[i] = code[i] ^ code[i + 1];
}
for (int i = 0; i <= l; i++)
{
num[i] = (code[i] - i) % 128;
}
printf("%s", num);
}
rsa
这种题google了一下rsa这种解密文件包的做法,主要就是用linux的openssl来解
题目思路:
pub.key了解一下rsa的文件解密,就会发现他其实是公钥,给E和N的,具体命令
openssl rsa -pubin -text -modulus -in warmup -in pub.key
得到16进制数字
python转换
s=''
int(s,16)
在线网站分解
然后python解密
CrackRTF
题目伪代码
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); //sha1加密
if ( !_strcmpi(String1, "6E32D0943418C2C33385BC35A1470250DD8923A9") )//md5加密
{
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;
}
正向流程:
先输入一个6位字符,然后后面加上@DBApp,再把六位字符转换数字一下,判定他是否小于六位,然后一个sha1加密再进行对比
像这种函数呢,google了一下是微软的一些官方加密函数,第二个参数是指运用什么加密算法
可以明显看到是sha1
接下来很明显是和一个md5字符串进行对比,但是和之前的截然不同,他是要获取这个rtf这个文件里面的资源文件AAA的头文件字符,然后进行md5加密
逆向过程:
先把sha1爆破出来,因为字符串转数字只能是6位,所以范围是100000,999999
写出爆破脚本,学了下hashlib这个库的用法
import hashlib
flag = "@DBApp"
for i in range(100000,999999):
s = str(i)+flag
x = hashlib.sha1(s.encode())
cnt = x.hexdigest()
if "6e32d0943418c2c" in cnt:
print(cnt)
print(str(i)+flag)
在打开ResourceHacker这个文件提取出rtf里面的aaa资源的头文件字符
因为也是6位,所以只需要截取前六位就好了
sub_401420这个函数里面对他进行了异或,我们照样操作就行
#include <stdio.h>
int main()
{
char enc[] = { 0x05, 0x7D, 0x41, 0x15,0x26,0x01,0x6D,0x53, 0x5D,0x40,0x5B,0x6D,0x21,0x24 };
char enc1[] = { 0x7b,0x5c,0x72,0x74,0x66,0x31 };
for (int i = 0; i <= 10; ++i)
{
enc[i] ^= enc1[i];
}
printf("%s", enc);
}
然后正常运行程序输入字符串就可以在当前文件夹得到一个rtf文件了,里面就有flag
flag{N0_M0re_Free_Bugs}
这道题经验:
先从题目的名字去分析,也不至于后面耗费那么多时间
这道题应该还能去动调直接得到第二个程序运行的结果,因为他先判断这个md5嘛,但是这个md5和题目运算出来的文件和flag并没有关系,所以跳过这个判断md5的应该也能得到flag
[FlareOn4]login
经典html,像这种可逆算法(个人觉得如果有异或,多项判断的没有取模的应该都是可逆算法)
直接看下html语法 输入这个比较字符串再打印出来就行了
[GUET-CTF2019]re
upx加壳,在仔细了看了看upx壳格式(hgame后遗症)没啥问题后,kali命令
upx -d
伪代码流程图
加密函数,经典方程式加密
直接上z3
要注意的是这里没有第七位,还有
16位和17位调换过来了,提取数据的时候要注意
上脚本
from z3 import *
a, c, b = Ints('a c b')
e, f, g = Ints('e f g')
h, i, k = Ints('h i k')
l, m, n = Ints('l m n')
o, p, q = Ints('o p q')
r, s, t = Ints('r s t')
u, v, w = Ints('u v w')
x1, y, z = Ints('x1 y z')
a1, b1, c1 = Ints('a1 b1 c1')
d1, e1, f1 = Ints('d1 e1 f1')
x = Solver()
x.add(a*1629056 == 166163712)
x.add(b*6771600 == 731332800)
x.add(c*10431000 == 1074393000)
x.add(e*3977328 == 489211344)
x.add(f*5138336 == 518971936)
x.add(g*7532250 == 406741500)
x.add(h*5551632 == 294236496)
x.add(i*3409728 == 177305856)
x.add(k*13013670 == 650683500)
x.add(l*6088797 == 298351053)
x.add(m*7884663 == 386348487)
x.add(n*8944053 == 438258597)
x.add(o*5198490 == 249527520)
x.add(p*4544518 == 445362764)
x.add(q*10115280 == 981182160)
x.add(r*3645600 == 174988800)
x.add(s* 9667504 == 493042704)
x.add(t* 5364450 == 257493600)
x.add(u* 13464540 == 767478780)
x.add(v* 5488432 == 312840624)
x.add(w* 14479500== 1404511500)
x.add(x1* 6451830 == 316139670)
x.add(y* 6252576 == 619005024)
x.add(z* 7763364 == 372641472)
x.add(a1* 7327320 == 373693320)
x.add(b1* 8741520 == 498266640)
x.add(c1* 8871876 == 452465676)
x.add(d1* 4086720 == 208422720)
x.add(e1* 9374400 == 515592000)
x.add(f1* 5759124 == 719890500)
check = x.check() //
print(check)
model = x.model()
print(model)
'''[f1 = 125,
e1 = 55,
d1 = 51,
c1 = 51,
b1 = 57,
a1 = 51,
z = 48,
y = 99,
x1 = 49,
w = 97,
v = 57,
u = 57,
t = 48,
s = 51,
r = 48,
q = 97,
p = 98,
o = 48,
n = 49,
m = 49,
l = 49,
k = 50,
i = 52,
h = 53,
g = 54,
f = 101,
e = 123,
c = 103,
b = 108,
a = 102]
'''
flag{e165421110ba03099a1c039337}
第七位爆破即可
[2019红帽杯]easyRE
伪代码流程
__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] = 127;
qmemcpy(v13, "y.i", 3);
v13[3] = 127;
qmemcpy(v14, "d`3w}wek9{iy=~yL@EC", sizeof(v14));
memset(v15, 0, sizeof(v15));
v16 = 0;
v17 = 0;
sub_4406E0(0LL, v15, 37LL);
v17 = 0;
if ( sub_424BA0(v15) == 36 )
{
for ( i = 0; i < (unsigned __int64)sub_424BA0(v15); ++i )
{
if ( (unsigned __int8)(v15[i] ^ i) != v12[i] )
{
result = 4294967294LL;
goto LABEL_13;
}
}
sub_410CC0("continue!");
memset(v18, 0, 0x40uLL);
v18[64] = 0;
sub_4406E0(0LL, v18, 64LL);
v18[39] = 0;
if ( sub_424BA0(v18) == 39 )
{
v2 = sub_400E44((__int64)v18);
v3 = sub_400E44(v2);
v4 = sub_400E44(v3);
v5 = sub_400E44(v4);
v6 = sub_400E44(v5);
v7 = sub_400E44(v6);
v8 = sub_400E44(v7);
v9 = sub_400E44(v8);
v10 = sub_400E44(v9);
v11 = sub_400E44(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;
}
一开始看上去很简单,不就是一个异或,然后不断地base64加密嘛
直到我看到了这个
然后就开始迷了,因为主函数就这些加密,好像似乎也没了
后来经过学长提醒,看了看elf的执行前运行的段init_array和fini_array段
ctrl+s找到这个段
这才发现真正的加密函数在这里
这里的话
思路:先要推出这前面数组四个字节是“flag”然后进行异或,得到字符串"&YA1"随后再对这个字符串进行异或
解密代码如下
#include <stdio.h>
#include <string.h>
int main()
{
char ida_chars[] =
{ 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 };
char key[] = { 0x40, 0x35, 0x20, 0x56 };
char key1[] = { "flag" };
char key2[6] = {0 };
char flag[26] = { 0 };
for (int i = 0; i < 5; i++)
{
key[i] ^= key1[i];
}
printf("%s\n", key);
for (int j = 0; j <25; j++)
{
flag[j] = ida_chars[j] ^ key[j % 4];
printf("%c", flag[j]);
}
}
经验:
这里乱用了一波strlen,导致乱码,后才发现,这个实际上不是字符串
[SUCTF2019]SignIn
看到数字65547就知道可能是rsa
正向过程:
输入字符串给a1a,转换一波格式,转成数字
然后进行一波rsa加密
最后比较
于是解密脚本
[MRCTF2020]Transform
教训:尽量不要用动态数组,这种未初始化的内存空间,对字符的控制挺差的
Youngter-drive
SThe quick brown fox jumps over the lazy dog.
#include <stdio.h>
#include <Windows.h>
int main()
{
char output[30] = "TOiZiZtOrYaToUwPnToBsOaOapsyS";
char enc[54] = "QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbnm";
char flag[64] = "0";
char *result;
for (int i = 0; i <= 30; i++)
{
if (i % 2 == 0)
{
flag[i] = output[i];
printf("%c", flag[i]);
}
else
{
if (97 < output[i] || output[i] > 122)
{
result = strstr(enc, output);
result += 96;
printf("%s", result);
}
else
{
result = strstr(enc, output);
result += 38;
printf("%s", result);
}
}
}
}
加密函数:
主要是找到output的字符在off_418000里面的位置,再加38和86
hgame fakeShell
直接用ida打开无果,应该是有反调试,因为是新生赛,去ctfwiki看看有什么反反调试方法
68CADA362C99068FB6254F152FAC2AB21EA41F663FAA8646934EB3320F45546253CCCD3BD5A611ABC0C28CD844D24A431601B0294D52D0555B60B812A7F450E6B9388B56A358C74C4B0719BF04631C18205D9B83A8679ABB285F0CB71BAF9C6C8A7DC50B2DA1902E0DED089DE4F9577E88A9DCFCDD806AE17940947FE9FFC826C33EAD751A2342E0CB9F105EDFD15C41A0CF02EF7159F103490A3487097CE861CEBAE3B5A28E27D305F81724519E69D939AEF77BC6FB6EC9EC2BFEBD35B195D4736BDE842282A533143D70EE7285DBEB21D6788992C1EA97E5F33C657AD7960E91E23174BE6F77FDF0C464E7763A4847F2FA3013F6006D981D375AB4818DF5BC00000000000000000051D341B615D274D02CF282FD7F000083EA72F66E55000010A0EBF66E550000E02DF28273750000000000000000000019742658C67F00006161616161616161616161616161616161616161616161616161616161616161002DF282FD7F00002B782658C67F00003E0000000000000020265B58C67F000070F172F66E5500000AC82558C67F000000000000000000000051D341B615D274002DF282FD7F0000D3ED72F66E55000020EE72F66E550000A0E172F66E557375646F0082FD7F00000051D341B615D27420EE72F66E55000040D82058C67F00000100000000000000E82DF282FD7F0000A0CC7D58010000001CED72F66E5500000000000000000000E9F9D17D04FF5871A0E172F66E550000E02DF282FD7F000000000000000000000000000000000000E9F9B1FB05167E24E9F9610EA0A30924000000000000000000000000000000000000000000000000F82DF282FD7F000068E17D58C67F00000B785C58C67F
init arrry
4E616D653A0966616B655368656C6C0A556D61736B3A09303030320A53746174653A0952202872756E6E696E67290A546769643A09333730390A4E6769643A09300A5069643A09333730390A505069643A09333531350A5472616365725069643A0933353B7F00000006AB6EBE74309202
gdb更换ptrace
程序主要逻辑就是两个RC4,然后对比,不过第一个RC4是被init_array赋值转换了key,w0wy0ugot1t,然后再rc4,动调赋值内存数据,得到hgame{s0meth1ng_run_bef0r_m4in?}
[HDCTF2019]Maze
###
这个kali脱壳有点问题,直接自己手动脱壳,这题的坑主要在于ida反汇编不对,因为有花指令的存在,总结了下,这个题应该是跳转到一个无效地址,让函数变成数据了,nop掉,按P框选红色区域就能反汇编成功了
看看各个函数的作用,sw应该是上下,ad应该是左右,加上是70个字符,变量值为7,推测格式为10*7
得出flagflag{ssaaasaassdddw}
[MRCTF2020]Xor
普通的异或
记得加M
#include <Stdio.h>
int main()
{
char flag[28] = "MSAWB~FXZ:J:`tQJ\"N@ bpdd}8g";
for (int i = 0; i < 27; i++)
{
flag[i] ^= i;
}
printf("%s", flag);
}//MRCTF{@_R3@1ly_E2_R3verse!}
[GWCTF 2019]xxor
考点z3
#include <cstdio>
void decode(int* a1)
{
for (int j = 0; j < 6; j++)
{
unsigned int v3; // [rsp+1Ch] [rbp-24h]
int a2[4] = { 2,2,3,4 };
unsigned int v4;
int flag;
int v5 = 74674557056;
v3 = a1[j];
v4 = a1[j+1];
for (int i = 0; i <= 0x3F; ++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[j]=v3;
a1[j+1]=v4;
j++;
}
}
int main()
{
int a1[6];
a1[2] = 3774025685;
a1[1] = 550153460;
a1[5] = -2064448480;
a1[0] = -548868226;
a1[3] = 1548802262;
a1[4] = 2652626477;
decode(a1);
for (int i = 0; i < 6; i++)
{
printf("%x",a1[i] );
}
printf("\n");
printf("%x", a1[4]);
printf("%x", a1[5]);
}
[MRCTF2020]hello_world_go
flag以明文存储
不过逆向起来,确实感觉有点难看出来
[WUSTCTF2020]level3
考点init_array
import base64
import string
str1 = "d2G0ZjLwHjS7DmOzZAY0X2lzX3CoZV9zdNOydO9vZl9yZXZlcnGlfD=="
string1 = "TSRQPONMLKJIHGFEDCBAUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
string2 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
a=str1.translate(str.maketrans(string1,string2))#利用密码表还原成正常base64编码后的字符串
#print(str1.translate(str.maketrans(string1,string2)))
print(base64.b64decode(a).decode())#base64解码
#wctf2020{Base64_is_the_start_of_reverse}
[FlareOn4]IgniteMe
加密逻辑就是一开始先异或v4,然后v4再等于字符串的现在遍历的字符,本来是挺简单的,想复杂了....,用了时间久一点
// [WUSTCTF2020]level3.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#include <iostream>
int main()
{
unsigned char byte_403000[40] = {
0x0D, 0x26, 0x49, 0x45, 0x2A, 0x17, 0x78, 0x44, 0x2B, 0x6C, 0x5D, 0x5E, 0x45, 0x12, 0x2F, 0x17,
0x2B, 0x44, 0x6F, 0x6E, 0x56, 0x09, 0x5F, 0x45, 0x47, 0x73, 0x26, 0x0A, 0x0D, 0x13, 0x17, 0x48,
0x42, 0x01, 0x40, 0x4D, 0x0C, 0x02, 0x69,0x0
};
int v4 = 4;
int v1 = 40;
char v5;
unsigned char byte_403078[40] = { 0 };
for (int i = v1 - 1; i >=0;-- i)
{
byte_403078 [i] = v4 ^ byte_403000[i];
v4 = byte_403078[i];
printf("%c", byte_403078[i]);
}
for (int i = 0; i < v1 - 1; i++)
{
char v5 = byte_403078[i];
if (v5 != 10 && v5 != 13)
{
if (v5)
byte_403078[i] = v5;
}
}
printf("\n");
printf("flag{");
for (int i = 0; i < v1 - 1; i++)
{
printf("%c", byte_403078[i]);
}
printf("}");
//flag{R_y0u_H0t_3n0ugH_t0_1gn1t3@flare-on.com}
}
[WUSTCTF2020]Cr0ssfun
check是一个经典比较函数
最近学了点cpp就用cpp写了
// [WUSTCTF2020]Cr0ssfun.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
//a1[1] == 99 && a1[25] == 64 && a1[27] == 101;
//a1[4] == 50 && a1[17] == 114 && a1[29] == 102 && a1[17] == 114 && a1[24] == 95
//a1[2] == 116
//&& a1[9] == 99
//&& a1[32] == 125
//&& a1[19] == 118
//&& a1[5] == 48
//&& a1[14] == 110
//a1[15] == 100 && a1[8] == 123 && a1[18] == 51 && a1[28] == 95 && a1[21] == 114
//* a1 == 119 && a1[6] == 50 && a1[22] == 's' && a1[31] == 'n' && a1[12] == '_'
//a1[7] == 48 && a1[16] == 95 && a1[11] == 112 && a1[23] == 101 && a1[30] == 117
//a1[10] == 112 && a1[13] == 64 && a1[3] == 102 && a1[26] == 114 && a1[20] == 101
#include <iostream>
int main()
{
std::string s1 = { 119,99,116,102, 50,48,50,48,123 ,99,112,112,95,64,110,100,95,114,51,118,101,114,115,101,95,64,114,101,95,102,117,110,125 };
std::cout << s1 << std::endl;
}
//wctf2020{cpp_@nd_r3verse_@re_fun}
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· 百万级群聊的设计实践
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性