BUUCTF NewStarCTF 2023 Week2 Reverse方向wp

文章目录

  • PZthon
  • AndroGenshin
  • SMC
  • C?C++?
  • R4ndom
  • Petals
  • easy_enc

PZthon

BUUCTF NewStarCTF 2023 Week2 Reverse方向wp_第1张图片
一个exe文件,用exeinfope先看看,Pyinstaller编译的,
可以使用pyinstxtractor反编译,这个网上搜一下很多的,具体使用就是

python pyinstxtractor.py 待反编译文件.exe

BUUCTF NewStarCTF 2023 Week2 Reverse方向wp_第2张图片
在这里插入图片描述
会生成一个文件夹,点进去找到PZthon.pyc
BUUCTF NewStarCTF 2023 Week2 Reverse方向wp_第3张图片

有一些pyc需要修补一下文件头,可以和struct.pyc一起拖入WinHex中对比一下。这里不需要,直接反编译就好,可以使用uncompyle6也可以网上找在线工具。这里随便找了个网站

# Visit https://www.lddgo.net/string/pyc-compile-decompile for more information
# Version : Python 3.9


def hello():
    art = '\n              ___                                                                      \n    //   ) )     / /    //   ) )  // | |     / /        // | |  \\ / / \\    / /       \n   //___/ /     / /    //        //__| |    / /        //__| |   \\  /   \\  / /        \n  / ____ /     / /    //  ____  / ___  |   / /        / ___  |   / /     \\/ /         \n //           / /    //    / / //    | |  / /        //    | |  / /\\     / /          \n//           / /___ ((____/ / //     | | / /____/ / //     | | / /  \\   / /           \n                                                                                       \n     / /        //   / / ||   / / //   / /  / /       /__  ___/ ||   / |  / / //   ) ) \n    / /        //____    ||  / / //____    / /          / /     ||  /  | / / //   / /  \n   / /        / ____     || / / / ____    / /          / /      || / /||/ / //   / /   \n  / /        //          ||/ / //        / /          / /       ||/ / |  / //   / /    \n / /____/ / //____/ /    |  / //____/ / / /____/ /   / /        |  /  | / ((___/ /     \n'
    print(art)
    return bytearray(input('Please give me the flag: ').encode())

enc = [
    115,
    121,
    116,
    114,
    110,
    76,
    37,
    96,
    88,
    116,
    113,
    112,
    36,
    97,
    65,
    125,
    103,
    37,
    96,
    114,
    125,
    65,
    39,
    112,
    70,
    112,
    118,
    37,
    123,
    113,
    69,
    79,
    82,
    84,
    89,
    84,
    77,
    76,
    36,
    112,
    99,
    112,
    36,
    65,
    39,
    116,
    97,
    36,
    102,
    86,
    37,
    37,
    36,
    104]
data = hello()
for i in range(len(data)):
    data[i] = data[i] ^ 21
if bytearray(enc) == data:
    print('WOW!!')
else:
    print('I believe you can do it!')
input('To be continue...')

一个简单的异或,写个exp

enc = [115, 121, 116, 114, 110, 76, 37, 96, 88, 116, 113, 112, 36, 97, 65, 125, 103, 37, 96, 114, 125, 65, 39, 112, 70, 112, 118, 37, 123, 113, 69, 79, 82, 84, 89, 84, 77, 76, 36, 112, 99, 112, 36, 65, 39, 116, 97, 36, 102, 86, 37, 37, 36, 104]

data = []
for i in range(len(enc)):
    data.append(chr(enc[i] ^ 21))
print("".join(data))

# flag{Y0uMade1tThr0ughT2eSec0ndPZGALAXY1eve1T2at1sC001}

AndroGenshin

BUUCTF NewStarCTF 2023 Week2 Reverse方向wp_第4张图片

JEB打开,看左侧,大概就是RC4+Base64的加密,点击MainActivity Tab反编译先

new int[]{0x7D, 0xEF, 101, 0x97, 77, 0xA3, 0xA3, 110, 58, 230, 0xBA, 206, 84, 84, 0xBD, 0xC1, 30, 0x3F, 104, 0xB2, 130, 0xD3, 0xA4, 94, 75, 16, 0x20, 33, 0xC1, 0xA0, 120, 0x2F, 30, 0x7F, 0x9D, 66, 0xA3, 0xB5, 0xB1, 0x2F, 0, 0xEC, 106, 107, 0x90, 0xE7, 0xFA, 16, 36, 34, 91, 9, 0xBC, 81, 5, 0xF1, 0xEB, 3, 54, 150, 40, 0x77, 202, 150})).equals(“YnwgY2txbE8TRyQecyE1bE8DZWMkMiRgJW1=”)) {

看到RC4那行,一直拉到最右边复制,能看到一串数据和一个base64解密。再结合上面有个key

先试试RC4

from Crypto.Cipher import ARC4
arr = [0x7D, 0xEF, 101, 0x97, 77, 0xA3, 0xA3, 110, 58, 230, 0xBA, 206, 84, 84, 0xBD, 0xC1, 30, 0x3F, 104, 0xB2, 130, 0xD3, 0xA4, 94, 75, 16, 0x20, 33, 0xC1, 0xA0, 120, 0x2F, 30, 0x7F, 0x9D, 66, 0xA3, 0xB5, 0xB1, 0x2F, 0, 0xEC, 106, 107, 0x90, 0xE7, 0xFA, 16, 36, 34, 91, 9, 0xBC, 81, 5, 0xF1, 0xEB, 3, 54, 150, 40, 0x77, 202, 150]
arrBytes = bytes(arr)
key = b"genshinimpact"
enc = ARC4.new(key)
base64_table = enc.decrypt(arrBytes)
print(base64_table)

# b'BADCFEHGJILKNMPORQTSVUXWZYbadcfehgjilknmporqtsvuxwzy1032547698/+'

果然解出一个base64码表,那就base64换表解一下

import base64

str1 = "YnwgY2txbE8TRyQecyE1bE8DZWMkMiRgJW1="
string1 = "BADCFEHGJILKNMPORQTSVUXWZYbadcfehgjilknmporqtsvuxwzy1032547698/+"    #替换的表
string2 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"

print (base64.b64decode(str1.translate(str.maketrans(string1,string2))))

# b'flag{0h_RC4_w1th_Base64!!}'

SMC

BUUCTF NewStarCTF 2023 Week2 Reverse方向wp_第5张图片
查一下壳,无壳 32bit vc++编写的

BUUCTF NewStarCTF 2023 Week2 Reverse方向wp_第6张图片
BUUCTF NewStarCTF 2023 Week2 Reverse方向wp_第7张图片

这里我尝试过jnz改成jmp,或者将中间全部nop掉,都没有用,进入动态调试还是一样会弹出。
应该是反调试,
BUUCTF NewStarCTF 2023 Week2 Reverse方向wp_第8张图片
把它nop掉就好。

下断点,动调后再修改汇编,
BUUCTF NewStarCTF 2023 Week2 Reverse方向wp_第9张图片
BUUCTF NewStarCTF 2023 Week2 Reverse方向wp_第10张图片
一直单步步过就好,JZ修改成JNZ;直到call eax;sub_403040处 用F7步入。 (修改用keypatch)或者Edit-Patch program)

忘记说了,这道题是SMC,也就是动态自修改代码,主函数第七行的VirtualProtect就是授予内存写权限,再用一些加密对内存进行改写,因为会在程序运行的时候进行自解密,所以不会影响程序的正常运行;目的是干扰静态分析。

这里步入403040处,程序就已经开始自解密了;

BUUCTF NewStarCTF 2023 Week2 Reverse方向wp_第11张图片

这里选择no,应该这里ida实际上已经不能正确识别eip入口了,我们手动处理一下

BUUCTF NewStarCTF 2023 Week2 Reverse方向wp_第12张图片

先点击 用 U 一下 ; 然后选中这个函数所有内容,用C转化为代码,记得Force强制。最后用P创建函数,再F5反编译一下。

BUUCTF NewStarCTF 2023 Week2 Reverse方向wp_第13张图片

逻辑很简单,逆向就是,用403020的值-5^0x11就好,点击4033D4就知道那里放到其实是我们的输入;

data = [0x7C, 0x82, 0x75, 0x7B, 0x6F, 0x47, 0x61, 0x57, 0x53, 0x25,
  0x47, 0x53, 0x25, 0x84, 0x6A, 0x27, 0x68, 0x27, 0x67, 0x6A,
  0x7D, 0x84, 0x7B, 0x35, 0x35, 0x48, 0x25, 0x7B, 0x7E, 0x6A,
  0x33, 0x71]

result = [chr((byte - 5) ^ 0x11 ) for byte in data]
print("".join(result))


# flag{SMC_1S_1nt3r3sting!!R1ght?}

C?C++?

BUUCTF NewStarCTF 2023 Week2 Reverse方向wp_第14张图片
程序查壳后发现是C#文件,用dnSpy反编译看看。

BUUCTF NewStarCTF 2023 Week2 Reverse方向wp_第15张图片
打开找到Main函数反编译。

BUUCTF NewStarCTF 2023 Week2 Reverse方向wp_第16张图片
根据加密逻辑逆向编写exp

array1 = [68,75,66,72,99,19,19,78,83,74,91,86,35,39,77,85,44,89,47,92,49,88,48,91,88,102,105,51,76,115,-124,125,79,122,-103]
test = [78,69,87,83,84,69,82]
for i in range(7):
    array1[i] -= i ^ -(test[i] % 4)
    array1[i+7] -= test[i] % 5
    array1[i+14] -= 2*i
    array1[i+21] -= i^2
    array1[i+28] -= test[i] // 5 + 10
for i in range(35):
    array1[i] -= i
    array1[i] += 32
    print(chr(array1[i]%256),end='')

# flag{45dg_ng38_d8b5_1a7d_gh47_kd5b}

R4ndom

BUUCTF NewStarCTF 2023 Week2 Reverse方向wp_第17张图片
64bit的ELF文件,

BUUCTF NewStarCTF 2023 Week2 Reverse方向wp_第18张图片
可以看到一个rand随机数,因为rand是伪随机,所以尝试一下动调;会发现动调行不通,那么应该就是有反调试,这里一开始没有找到的,因为之前只接触过isdebuggerpresent,后面才知道是linux的反调试

学习:https://xz.aliyun.com/t/6882

BUUCTF NewStarCTF 2023 Week2 Reverse方向wp_第19张图片
这题的函数很少,这个a很显眼,点进去看看就知道了,ptrace反调试,可以patch掉绕过。
一开始本身是打算动调然后找到42个随机数的,但是发现很麻烦,所以选择找随机数种子,也就是下面的b;
BUUCTF NewStarCTF 2023 Week2 Reverse方向wp_第20张图片
倒回去看加密的逻辑,Table表:
BUUCTF NewStarCTF 2023 Week2 Reverse方向wp_第21张图片
这里就是用我们的输入和随机数相加作为table表的索引,最后得到的值就是s2;
由于这里随机数在windows和linux环境下得到的结果不同,所以要在linux环境中运行我们的脚本;

#include 
#include 
#include 
__uint8_t Table[256] = {    0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76,    			 		
							0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0,   
 							0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15,    				
 							0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75,    
 							0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84,    
 							0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF,    
 							0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8,    
 							0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2,    
 							0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73,    
 							0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB,    
 							0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79,    
 							0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08,    
 							0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A,    
 							0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E,    
 							0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF,    
 							0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16
 						};
int main(){  
srand(1400333646);    
__uint8_t enc[42] = {  	0xEE, 0xE6, 0xD7, 0xB2, 0x8A, 0xAB, 0x13, 0x35, 0x02, 0x7B, 0xC9, 0xB9, 0x9C, 0xBA, 0xED, 0x2E,       
			 			0xBD, 0x4F, 0xFA, 0xEE, 0xC8, 0xF8, 0xE4, 0x16, 0x82, 0x63, 0x3B, 0x98, 0xF4, 0x14, 0x30, 0x38,        
			 			0x07, 0x36, 0x84, 0x3D, 0x0C, 0x36, 0x32, 0xEA, 0x55, 0xA6};    
 
 for (int i = 0; i < 42; ++i){        
 		for (int j = 0; j < 256; ++j){           
			  if (Table[j] == enc[i]){                
			  		printf("%c", (j - rand() % 255));          
			     }        
			}   
	}    
return 0;
}

// flag{B8452786-DD8E-412C-E355-2B6F27DAB5F9}

Petals

BUUCTF NewStarCTF 2023 Week2 Reverse方向wp_第22张图片
64bit 的 ELF文件

BUUCTF NewStarCTF 2023 Week2 Reverse方向wp_第23张图片
BUUCTF NewStarCTF 2023 Week2 Reverse方向wp_第24张图片
地址爆红;
BUUCTF NewStarCTF 2023 Week2 Reverse方向wp_第25张图片
花指令,JZ和JNZ互补跳转,将call patch掉就好,
BUUCTF NewStarCTF 2023 Week2 Reverse方向wp_第26张图片

再用P创建函数 F5反编译
BUUCTF NewStarCTF 2023 Week2 Reverse方向wp_第27张图片
BUUCTF NewStarCTF 2023 Week2 Reverse方向wp_第28张图片
修补后可以看到传入的一个是我们的输入,一个是输入长度,也就是后面的a1和a2;
第一个for 前面是Byte类型的,默认一个字节,这里在后面写exp的时候:

v5[i] = (~(i ^ 25)) & 0xff

使用 & 0xff 做一个掩码操作; 0xff在二进制中是11111111,跟0xff进行与操作可以将其他位数清零,确保只剩下8bit大小的;

第二个for 就是,我们的输入作为v6的索引,将得到的值存入a1中,最后返回,a1和&unk_4020比较,也就是说unk_4020的值在v6中的索引,就是我们要的flag。

最后还有个md5

exp:

import hashlib

enc = [0xD0, 0xD0, 0x85, 0x85, 0x80, 0x80, 0xC5, 0x8A, 0x93, 0x89,
       0x92, 0x8F, 0x87, 0x88, 0x9F, 0x8F, 0xC5, 0x84, 0xD6, 0xD1,
       0xD2, 0x82, 0xD3, 0xDE, 0x87]
v5 = [0] * 256
for i in range(256):
    v5[i] = (~(i ^ 25)) & 0xff
flag = ''
for i in range(len(enc)):
    flag += chr(v5.index((enc[i]) % 256))
print(flag)
print(hashlib.md5(flag.encode()).hexdigest())

# flag{d780c9b2d2aa9d40010a753bc15770de}

easy_enc

BUUCTF NewStarCTF 2023 Week2 Reverse方向wp_第29张图片
BUUCTF NewStarCTF 2023 Week2 Reverse方向wp_第30张图片
Shift+F12搜索字符串,定位到关键函数处,

观察下面:整体的逻辑就是对输入的字符串进行四次加密,然后和buf1和v9比较;成功就是flag的;
这里注意的是Buf1 和 v9 在内存上的布局是连在一起的,也就是v9也可以看作是Buf1的一部分;

BUUCTF NewStarCTF 2023 Week2 Reverse方向wp_第31张图片
观察一下四个加密过程;
第一个:
BUUCTF NewStarCTF 2023 Week2 Reverse方向wp_第32张图片
分三个if,分别是大写字母,小写字母和数字,简化一下就是分别做加法;
第二个:

BUUCTF NewStarCTF 2023 Week2 Reverse方向wp_第33张图片
和“NewStarCTF”里的值循环相加,用了一个 i % 10;

第三个和第四个分别用了一个取反和,一个*52;
BUUCTF NewStarCTF 2023 Week2 Reverse方向wp_第34张图片
BUUCTF NewStarCTF 2023 Week2 Reverse方向wp_第35张图片
因为 第四个加密 *52 没有办法逆向,所以这里采用单字符爆破的方式;

#include 
#include 
int main(void){
	int enc1[100] = {0xE8, 0x80, 0x84, 0x08, 0x18, 0x3C, 0x78, 0x68, 0x00, 0x70,
        0x7C, 0x94, 0xC8, 0xE0, 0x10, 0xEC, 0xB4, 0xAC, 0x68, 0xA8,
        0x0C, 0x1C, 0x90, 0xCC, 0x54, 0x3C, 0x14, 0xDC, 0x30};
    char enc2[20] = "NewStarCTF";
    char flag[50];
    int i, j;
    for ( i = 0; i < 29; ++i){
    	for (j = 32; j < 127; j++){
    		int tmp = j;
    		if (j >= 'A' && j <= 'Z'){
    			j = (j - 'A' + 13) % 26 + 'A';
    			}
			else if (j >= '0' && j <= '9'){
    			 j = (j - '0' + 3) % 10 + '0';
				}
			else if (j >= 'a' && j <= 'z'){
    			j = (j - 'a' + 8) % 26 + 'a';
				}
			j += enc2[i % strlen(enc2)];
			j = ~j;
			j = (j*52)&0xff;
			if (j == enc1[i]){
				if ((tmp >= 'A' && tmp <= 'Z') ||(tmp >= 'a' && tmp <= 'z') ){
					printf("%c", tmp);
				}
			}
			j = tmp;
		}
	
	}
	return 0;
}

上面是爆破脚本;
有一点要注意;代码处加密时都用了 (BYTE) 限制了 数据的大小为 一个字节;
所以最后这里要 &0xff 以确保
52后不会超出可读ascii的范围;

j = (j*52)&0xff;

也可以使用__uint8_t来声明变量,__uint8_t 是一个无符号 8 位整数类型;通常用于确保一个变量始终被解释为一个 8 位无符号整数,而不受编译器的默认类型推断影响;但是我电脑配置环境不允许我用/(ㄒoㄒ)/~~哎;

没了没了,还有最后一题安卓逆向的写不来,博主还不会/(ㄒoㄒ)/~~加油咯。

你可能感兴趣的:(CTF比赛WP,CTF学习笔记,网络安全,汇编,python,c语言)