REVERSE-COMPETITION-GeekChallenge2021

Re0

64位exe,ida打开,main函数中没发现什么重要的逻辑
Shift+F12打开字符串窗口,直接找到flag明文
Re0-flag

刘壮桌面美化大师

apk文件,jadx-gui打开,MainActivity中什么都没有,于是查看与MainActivity在同一目录下的其它类
在DesktopbeautifierConfigureActivityKt类里面找到一个好像和flag相关的方法loadTitlePref
desk-main
loadTitlePref要获取R.string.flag,我们跟过去发现只是一个整型,实际上是一个资源id
desk-resid
在android中,一个资源id和一个实际的资源绑定,而这个实际的资源在资源文件res中
于是在如下位置找到flag
desk-flag

买Activity

apk文件,加载了buyactivity库,MainActivity大概作用是保存输入到一个msgList里,没什么大用,于是Msg和MsgAdapter这两个类就不用看了
查看ExportedActivity这个类,发现可以直接在一个文本框打印flag
activity-main
来到Decode类,从本地获取一个字符串,然后对这个字符串顺序异或16即为flag
activity-decode
这个时候可以直接用jeb调试smali,指定启动ExportedActivity即可获得flag
这里我们按照getDecodedFlag方法的逻辑计算flag
ida打开libbuyactivity.so,来到Java_com_sorrowrain_buyactivity_Decode_stringFromNative
可以看到两个字符串和一些操作,下面的操作一时看不懂,直接将两个字符串拼接,然后顺序异或16
activity-so
可以看到两个字符串拼接顺序异或16后,得到的字符串中含有"{}",说明这个字符串大概率就是flag,但是顺序不对

s="CSD!Os!yiyO#|iU`bu1Ikxc$dFdOCBq!Oh dtm"
flag=""
for c in s:
    flag+=chr(ord(c)^16)
print(flag)
# SCT1_c1iyi_3lyEpre!Y{hs4tVt_SRa1_x0td}

看着像栅栏,直接用工具,栏数为2,得到flag
解栅栏前:
activity-fakeflag
解栅栏后:
activity-flag

Re1

64位的exe,ida打开
主要的逻辑在main函数中,输入的长度为44,输入经标准base64变换后与0x40异或,最后与data比较
在这里插入图片描述
取出data的数据,写逆脚本即可

import base64
res=[21,113,44,4,37,113,40,16,21,44,121,40,34,45,18,38,25,45,6,58,26,20,
     25,112,24,114,6,57,26,22,121,112,33,7,22,38,25,45,6,58,33,24,14,38,
     34,114,26,38,35,45,22,114,26,24,10,58,26,24,112,125]
for i in range(len(res)):
    res[i]^=0x40
flag="".join(chr(i) for i in res)
print(base64.b64decode(flag))
# SYC{XOR_and_base64_are_the_basis_of_reverse}

调试

64位elf,反编译main函数后就只有一个字符串拷贝
查看main函数的汇编代码,在偏移0x144C处有一条jnz条件跳转指令,如果[rbp+var_144]非零则跳转到loc_1455,但是在偏移0x1382处给[rbp+var_144]赋值为0,所以ida反编译到jnz就判定为不跳转,进而jmp到loc_14A0即main函数结束处
debug-main
我们看到loc_1455中偏移为0x146B处调用了sub_11C8函数,根据函数调用约定可知上面拷贝来的字符串作为参数传入了sub_11C8函数进行处理
于是可以猜测出题人就是想通过上述不执行jnz条件跳转的方式来隐藏flag
debug-call
这里我们先去看一下sub_11C8函数,ida分析sub_11C8失败,先在偏移0x11C8处右键->undefine
debug-undefine
我们知道函数的开头一般是push rbp,机器码为0x55,于是在偏移0x11CD处,按c将数据转为代码,再按p创建函数,反编译后得到
debug-func
sub_11CD没看懂什么逻辑,实际上也不需要看懂
出题人通过不执行sub_11CD的方式来隐藏flag,于是我们可以patch程序,将jnz改写成jz,如图
debug-patch
保存后,直接运行elf,即可得到flag
debug-flag
或者不patch程序,根据题目的提示,用ida远程调试elf的时候,在执行jnz之前将零标志位的值修改为0即可将程序流引向执行sub_11CD,进而获得flag

珍惜生命

.pyc文件,用uncompyle6来反编译
输入flag和key,flag长度为51,key长度为8
验证key经过多元方程组运算后是否与"Syclover"相同,然后输入的flag中{}中包含的内容与key做循环异或,结果与一个给定的flag元组比较,验证输入的flag是否正确

def Challenge():
    import sys
    print("Welcome to py's world")
    S = input('plz give me your flag:')
    Key = input('plz give me your key(string):')
    if len(S) != 51 or len(Key) != 8:
        print("the flag's or key's strlen...")
        sys.exit()
    else:
        tmp = S[4:50]
        KEY_cmp = 'Syclover'
        key = []
        key_cmp = ''
        for i in Key:
            key.append(ord(i))

        try:
            key_cmp += chr((key[1] * key[2] - key[5] * 72 - key[4] * 3 - key[3] ^ key[1] + (key[3] << 2) + key[2] * 6 - key[7] & key[6] - 1000) - 14)
            key_cmp += chr((key[5] * 7 + key[3] * 3 + key[2] + key[6] - (key[2] >> 2) - key[1] ^ key[0] + key[7] + (key[4] ^ key[1]) + (key[4] | key[7])) - 801)
            key_cmp += chr((key[6] * 5 + key[2] * 6 - key[3] * 7 + key[4] | key[5] + key[4] * 10 + key[0] ^ key[1] * 3 - key[7] + key[0] + key[1]) - 924)
            key_cmp += chr(key[1] * 3 + key[5] * 9 + key[0] + key[2] * 2 + key[3] * 5 - key[4] * (key[6] ^ key[7]) + 321 - 16)
            key_cmp += chr((key[5] * 12 - key[0] ^ key[6] - key[3] * 23 + key[4] * 3 + key[2] * 8 + key[1] - key[7] * 2 + key[6] * 4 + 1324) + 1)
            key_cmp += chr(key[3] * 54 - key[1] * 3 + key[2] * 3 + key[4] * 11 - key[5] * 2 + key[0] + key[7] * 3 - key[6] - 6298 + 40)
            key_cmp += chr(key[7] - key[6] * key[3] + key[2] * key[2] - key[4] * 32 + key[5] * (key[0] >> 2) - key[1] * key[1] - 6689 + 41)
            key_cmp += chr((key[5] - key[3] * 41 + key[6] * 41 + key[5] ^ (key[4] & key[6] | key[0]) - (key[7] * 24 | key[2]) + key[1] - 589) - 36)
        except ValueError:
            print("You know what I'm going to say...")
            sys.exit()

        if key_cmp != KEY_cmp:
            print("You know what I'm going to say...")
            sys.exit()
        flag = [
         113, 74, 71, 35, 29, 91, 29, 12, 114, 73, 60, 52, 69, 5, 113, 35, 95, 38, 20, 112, 95, 7, 74, 12, 102, 23, 7, 31, 87, 5, 113, 98, 85, 38, 16, 112, 29, 6, 30, 12, 65, 73, 83, 36, 12, 23]
        for i in range(46):
            if ord(tmp[i]) ^ key[((i + 1) % len(key))] != flag[i]:
                print("You know what I'm going to say...")
                sys.exit()

        print('Yeah!Submit your flag in a hurry~')

Challenge()

核心在求解key,用z3解多元方程组即可,需要注意两个地方
1、用BitVec定义变量时需要是16位,笔者开始用8位,一直解不出来
2、此方程组多解,要用while s.check()==sat来输出多组解,需要的是key的8个值都小于128的一组解

from z3 import *
key=[BitVec("key[%d]"%i,16) for i in range(8)]
KEY_cmp="Syclover"
KEY_num=[ord(c) for c in KEY_cmp]
s=Solver()
s.add(((key[1] * key[2] - key[5] * 72 - key[4] * 3 - key[3] ^ key[1] + (key[3] << 2) + key[2] * 6 - key[7] & key[6] - 1000) - 14)==KEY_num[0])
s.add(((key[5] * 7 + key[3] * 3 + key[2] + key[6] - (key[2] >> 2) - key[1] ^ key[0] + key[7] + (key[4] ^ key[1]) + (key[4] | key[7])) - 801)==KEY_num[1])
s.add(((key[6] * 5 + key[2] * 6 - key[3] * 7 + key[4] | key[5] + key[4] * 10 + key[0] ^ key[1] * 3 - key[7] + key[0] + key[1]) - 924)==KEY_num[2])
s.add((key[1] * 3 + key[5] * 9 + key[0] + key[2] * 2 + key[3] * 5 - key[4] * (key[6] ^ key[7]) + 321 - 16)==KEY_num[3])
s.add(((key[5] * 12 - key[0] ^ key[6] - key[3] * 23 + key[4] * 3 + key[2] * 8 + key[1] - key[7] * 2 + key[6] * 4 + 1324) + 1)==KEY_num[4])
s.add((key[3] * 54 - key[1] * 3 + key[2] * 3 + key[4] * 11 - key[5] * 2 + key[0] + key[7] * 3 - key[6] - 6298 + 40)==KEY_num[5])
s.add((key[7] - key[6] * key[3] + key[2] * key[2] - key[4] * 32 + key[5] * (key[0] >> 2) - key[1] * key[1] - 6689 + 41)==KEY_num[6])
s.add(((key[5] - key[3] * 41 + key[6] * 41 + key[5] ^ (key[4] & key[6] | key[0]) - (key[7] * 24 | key[2]) + key[1] - 589) - 36)==KEY_num[7])
while s.check():
    print(s.model())
# [key[6] = 54,
#  key[1] = 38,
#  key[3] = 99,
#  key[0] = 83,
#  key[7] = 46,
#  key[2] = 121,
#  key[5] = 45,
#  key[4] = 64]

最后key与flag循环异或即可得到flag

flag = [113, 74, 71, 35, 29, 91, 29, 12, 114, 73, 60, 52, 69, 5, 113, 35, 95, 38, 20, 112, 95, 7, 74, 12, 102, 23, 7, 31, 87, 5, 113, 98, 85, 38, 16, 112, 29, 6, 30, 12, 65, 73, 83, 36, 12, 23]
key=[0]*8
key[6] = 54
key[1] = 38
key[3] = 99
key[0] = 83
key[7] = 46
key[2] = 121
key[5] = 45
key[4] = 64
for i in range(len(flag)):
    flag[i]^=key[(i+1)%len(key)]
print("SYC{"+"".join(chr(i) for i in flag)+"}")
# SYC{W3$c0m3_T0_th3_py_w0r1d_@nd_z3_1s_s0000_g00d!!}

new_language

32位.Net程序,dnSpy打开,来到Main
text为输入,长度为38,将输入作为下标从sbox中取值,保存到array中,然后array与已知的array2比较
net-main
取出sbox和array2,写逆运算脚本即可得到flag

sbox=[99,
			124,
			119,
			123,
			242,
			107,
			111,
			197,
			48,
			1,
			103,
			43,
			254,
			215,
			171,
			118,
			202,
			130,
			201,
			125,
			250,
			89,
			71,
			240,
			173,
			212,
			162,
			175,
			156,
			164,
			114,
			192,
			183,
			253,
			147,
			38,
			54,
			63,
			247,
			204,
			52,
			165,
			229,
			241,
			113,
			216,
			49,
			21,
			4,
			199,
			35,
			195,
			24,
			150,
			5,
			154,
			7,
			18,
			128,
			226,
			235,
			39,
			178,
			117,
			9,
			131,
			44,
			26,
			27,
			110,
			90,
			160,
			82,
			59,
			214,
			179,
			41,
			227,
			47,
			132,
			83,
			209,
			0,
			237,
			32,
			252,
			177,
			91,
			106,
			203,
			190,
			57,
			74,
			76,
			88,
			207,
			208,
			239,
			170,
			251,
			67,
			77,
			51,
			133,
			69,
			249,
			2,
			127,
			80,
			60,
			159,
			168,
			81,
			163,
			64,
			143,
			146,
			157,
			56,
			245,
			188,
			182,
			218,
			33,
			16,
			255,
			243,
			210,
			205,
			12,
			19,
			236,
			95,
			151,
			68,
			23,
			196,
			167,
			126,
			61,
			100,
			93,
			25,
			115,
			96,
			129,
			79,
			220,
			34,
			42,
			144,
			136,
			70,
			238,
			184,
			20,
			222,
			94,
			11,
			219,
			224,
			50,
			58,
			10,
			73,
			6,
			36,
			92,
			194,
			211,
			172,
			98,
			145,
			149,
			228,
			121,
			231,
			200,
			55,
			109,
			141,
			213,
			78,
			169,
			108,
			86,
			244,
			234,
			101,
			122,
			174,
			8,
			186,
			120,
			37,
			46,
			28,
			166,
			180,
			198,
			232,
			221,
			116,
			31,
			75,
			189,
			139,
			138,
			112,
			62,
			181,
			102,
			72,
			3,
			246,
			14,
			97,
			53,
			87,
			185,
			134,
			193,
			29,
			158,
			225,
			248,
			152,
			17,
			105,
			217,
			142,
			148,
			155,
			30,
			135,
			233,
			206,
			85,
			40,
			223,
			140,
			161,
			137,
			13,
			191,
			230,
			66,
			104,
			65,
			153,
			45,
			15,
			176,
			84,
			187,
			22]
array2=[64,
				249,
				133,
				69,
				146,
				253,
				253,
				207,
				182,
				4,
				157,
				207,
				251,
				4,
				60,
				81,
				59,
				77,
				146,
				77,
				207,
				26,
				38,
				207,
				64,
				77,
				177,
				77,
				64,
				195,
				77,
				253,
				253]
flag=[]
for i in range(len(array2)):
    for j in range(len(sbox)):
        if sbox[j]==array2[i]:
            flag.append(j)
            break
print("SYC{"+"".join(chr(i) for i in flag)+"}")
# SYC{right!!_y0u_c0mpIete_C#_reVer3e!!}

easypyc

python打包成的exe,用pyinstxtractor脚本解包
uncompyle6反编译easypyc.pyc失败,原因是解包后的easypyc.pyc文件魔数被破坏,需要修正正确
此为被破坏的easypyc.pyc文件
pyc-pyc
想要修正easypyc.pyc需要对照同目录下的struct.pyc进行修正,如图
pyc-struct
此为修正后的easypyc.pyc文件
pyc-rightpyc
保存后再用uncompyle6反编译

whatbox = [
 0] * 256

def aaaaaaa(a, b):
    k = [
     0] * 256
    t = 0
    for m in range(256):
        whatbox[m] = m
        k[m] = ord(a[(m % b)])
    else:
        for i in range(256):
            t = (t + whatbox[i] + k[i]) % 256
            temp = whatbox[i]
            whatbox[i] = whatbox[t]
            whatbox[t] = temp


def bbbbbbbbbb(a, b):
    q = 0
    w = 0
    e = 0
    for k in range(b):
        q = (q + 1) % 256
        w = (w + whatbox[q]) % 256
        temp = whatbox[q]
        whatbox[q] = whatbox[w]
        whatbox[w] = temp
        e = (whatbox[q] + whatbox[w]) % 256
        a[k] = a[k] ^ whatbox[e] ^ 102 #魔改,多异或了一个102


def ccccccccc(a, b):
    for i in range(b):
        a[i] ^= a[((i + 1) % b)]
    else:
        for j in range(1, b):
            a[j] ^= a[(j - 1)]


if __name__ == '__main__':
    kkkkkkk = 'Geek2021'
    tttttt = [117, 62, 240, 152, 195, 117, 103, 74, 240, 151, 173, 162, 17, 75, 141, 165, 136, 117, 113, 33, 98, 151, 174, 4, 48, 25, 254, 101, 185, 127, 131, 87]
    ssss = input('Please input your flag:')
    inp = [0] * len(ssss)
    if len(ssss) != 32:
        print('Length Error!!!!')
        exit(0)
    for i in range(len(ssss)):
        inp[i] = ord(ssss[i])
    else:
        aaaaaaa(kkkkkkk, len(kkkkkkk))
        bbbbbbbbbb(inp, 32)
        ccccccccc(inp, 32)
        for m in range(32):
            if tttttt[m] != inp[m]:
                raise Exception('sorry your flag is wrong')
            print('success!!!!!!')
            print('your flag is {}'.format(ssss))

aaaaaaa和bbbbbbbbbb是魔改了一点的RC4,最后异或的时候多异或了一个102,解RC4的时候要加上,密钥为"Geek2021"
ccccccccc对RC4加密后的密文进行异或运算,结果与tttttt比较
先逆ccccccccc解得正确的RC4密文

tttttt = [117, 62, 240, 152, 195, 117, 103, 74, 240, 151, 173, 162, 17, 75, 141, 165, 136, 117, 113, 33, 98, 151, 174, 4, 48, 25, 254, 101, 185, 127, 131, 87]
for i in range(len(tttttt)-1,0,-1):
    tttttt[i]^=tttttt[i-1]
tttttt[len(tttttt)-1]^=tttttt[0]
for i in range(len(tttttt)-2,-1,-1):
    tttttt[i]^=tttttt[i+1]
print(tttttt)
# [34, 87, 28, 210, 186, 225, 87, 69, 104, 210, 181, 143, 128, 51, 105, 175, 135, 170, 87, 83, 3, 64, 181, 140, 38, 18, 59, 220, 71, 155, 93, 161]

再解魔改RC4即可得到flag

#include<stdio.h>
void rc4_init(unsigned char* s, unsigned char* key, unsigned long Len_k)
{
	int i = 0, j = 0;
	char k[256] = { 0 };
	unsigned char tmp = 0;
	for (i = 0; i < 256; i++) {
		s[i] = i;
		k[i] = key[i % Len_k];
	}
	for (i = 0; i < 256; i++) {
		j = (j + s[i] + k[i]) % 256;
		tmp = s[i];
		s[i] = s[j];
		s[j] = tmp;
	}
}

/*
RC4加解密函数
unsigned char* Data     加解密的数据
unsigned long Len_D     加解密数据的长度
unsigned char* key      密钥
unsigned long Len_k     密钥长度
*/
void rc4_crypt(unsigned char* Data, unsigned long Len_D, unsigned char* key, unsigned long Len_k) //加解密
{
	unsigned char s[256];
	rc4_init(s, key, Len_k);
	int i = 0, j = 0, t = 0;
	unsigned long k = 0;
	unsigned char tmp;
	for (k = 0; k < Len_D; k++) {
		i = (i + 1) % 256;
		j = (j + s[i]) % 256;
		tmp = s[i];
		s[i] = s[j];
		s[j] = tmp;
		t = (s[i] + s[j]) % 256;
		Data[k] = Data[k] ^ s[t]^102; //这里加一个异或102
	}
}
void main()
{
	//密钥
	unsigned char key[] = "Geek2021";
	unsigned long key_len = sizeof(key) - 1;
	//密钥
	//unsigned char key[] = {};
	//unsigned long key_len = sizeof(key);

	//密文
	unsigned char data[] = { 34, 87, 28, 210, 186, 225, 87, 69, 104, 210, 181, 143, 128, 51, 105, 175, 135, 170, 87, 83, 3, 64, 181, 140, 38, 18, 59, 220, 71, 155, 93, 161 };
	//解密
	rc4_crypt(data, sizeof(data), key, key_len);
	for (int i = 0; i < sizeof(data); i++)
	{
		printf("%c", data[i]);
	}
	printf("\n");
	return;
}
//SYC{Just_a_Eeeeeeasy_Rc4_right?}

Brute_force

64位exe,ida打开,go语言,左侧函数窗找到main_main
要求运行时加参数,且参数的长度为24
进入main_unnamed630函数,第40行有一个main_encode函数,做了md5散列,返回十六进制摘要
直接在ida中调试一下,断点下在main_unnamed630函数第49行调用runtime_memequal函数前
参数设置为一段长度为24的字符串,如图
brute-argset
程序运行后在此处断下
v15指向我们的输入经main_encode函数处理返回的十六进制摘要,此时为"e2fc714c4727ee9395f324cd2e7f331f"
v19指向要去比较的长度为32的md5十六进制摘要,此时为"957a3926d4ff16d0d3bac4ed3044537b"
brute-debug
通过在线网站查询到v15指向的字符串就是我们输入的前四个字符"abcd"的md5十六进制摘要
brute-md5
那么这题的流程就是将长度为24的输入分成6组,每组4个字符,对每组进行md5散列,返回散列值的十六进制摘要,与已知的长度为32的md5十六进制摘要比较,从而验证输入
每组4个字符,每个字符的ascii码范围为[48,128),可爆破,和题目名称呼应
"957a3926d4ff16d0d3bac4ed3044537b"只是第1组要去比较的md5十六进制摘要,其他5组可通过调试得到
最后全部6组md5十六进制摘要和爆破脚本如下

# -*- coding:utf-8 -*-
import hashlib
s="957a3926d4ff16d0d3bac4ed3044537b"
#s="d7bf94ada03842f20934c5605728fbc5"
#s="5781f597ce91fb5f66057f35846bcb78"
#s="ae4b9b5b2468a3d15b6b8690b761e160"
#s="4ad50c4af2c5beda7aca217afbac9bd6"
#s="f40b339be4c5898741b8a0d2a8007bd5"
for i0 in range(48,128):
    for i1 in range(48, 128):
        for i2 in range(48, 128):
            for i3 in range(48, 128):
                flag=chr(i0)+chr(i1)+chr(i2)+chr(i3)
                h=hashlib.md5()
                h.update(flag.encode(encoding='utf-8'))
                if h.hexdigest()==s:
                    print(flag)
                    exit()
# 7h3_g0_pr0g@rm_13_slgned

win32

题目名为win32,实际是个64位的exe,upx脱壳,ida打开
题目描述中提到了base64,猜测可能是变表base64
交叉引用Str2来到sub_140011B80函数,主要逻辑在case 0x111处
输入传入sub_1400110F5函数处理,结果放入变量Str1中,与已知的Str2比较,验证输入
win32-base64
进入sub_1400110F5->sub_140011F90
sub_140011F90函数构造了一个表,和标准的base64表是一样的,下面就是正常的base64算法
win32-table
直接解Str2的base64即可得到flag
win32-flag

wasm

wasm逆向参考:一种Wasm逆向静态分析方法
使用wasm2c将.wasm文件转为.c文件,对.c文件用gcc只编译不链接得到.o文件
ida分析.o文件,w2c_main->w2c_f11
大概的逻辑如下图,判断输入的长度是否等于22,w2c_f10对输入进行变换,w2c_f9对变换后的输入进行比较验证
wasm-main
进入w2c_f10函数,唯一的参数就是我们的输入
看到循环体里有一个异或0x66的运算,结合题目文件名xorwasm,这个异或0x66的运算可能有很大作用
wasm-xor
之前猜测w2c_f9是对变换后的输入进行比较验证的函数,但是跟进去分析并没有找到最后要去比较的数据
参考博客里写道,“对于wasm,所有的字符串会被存放在二进制文件的末尾,以此能获取一些关键的信息”
wasm-const
而且在ida字符串窗口中也能找到一些明文字符串
wasm-strings
在Hex View中找到这些明文字符串,可以看到在"infinity"这个有意义的单词前正好有22个数据,猜测这些数据就是最后要去比较的数据
wasm-hex
直接取出这22个数据,异或0x66后即可得到flag

arr=[0x35, 0x3f, 0x25, 0x1d, 0x11, 0x07, 0x15, 0x0b, 0x39, 0x2f, 0x15, 0x39,
  0x35, 0x56, 0x39, 0x21, 0x09, 0x56, 0x02, 0x47, 0x47, 0x1b]
for i in range(len(arr)):
    arr[i]^=0x66
print("".join(chr(i) for i in arr))
# SYC{wasm_Is_S0_Go0d!!}

猜拳

64位exe,加了upx壳,但是工具脱不掉壳
根据提示"API断点"猜测可能是通过调试器对按钮相关的API下断点,程序停下来后修改寄存器的值,从而改变程序执行流,得到flag
程序直接扔进x64dbg,然后F9会被程序检测到调试器从而结束进程
这时我们先运行程序,然后让x64dbg去附加(attach)到运行中的程序
附加成功后,右键->搜索->所有模块->字符串
可以发现一些明文字符串
game-strings
双击字符串"Congratulations on getting the flag"(相当于ida中的交叉引用),找到引用该字符串的指令
game-getflag
我们看到该字符串的上方有一条"Sycl0v3r"的字符串,还有一条"call re.7FF7A77E13D8"的指令
多次调试发现,程序将"Sycl0v3r"作为密钥传入0x7FF7A77E13D8处的函数,对密文进行解密,返回flag
在上图标红处,即"00007FF7A77E1567"处,右键->设置新的运行点,将rip设置到此处
随后F8单步步过,在"call re.7FF7A77E13D8"这条指令执行后即可得到flag
game-flag

have_a_tea

64位ELF,start函数中存在SMC,在偏移0x1A2F处下断点
tea-debug
启动调试,程序断下来后,F8来到偏移0x0870处
tea-debug
再多按几次F8,来到偏移0x1361处
tea-debug
之后可以不用按F8,往下走,来到偏移0x14C6处,可以看到"db 55h"
我们知道"push rbp"的机器码为0x55,于是这里就是一个函数的起始地址
tea-debug
在偏移0x14C6处按c,将数据转成代码,再按p创建函数,然后F5反编译
tea-debug
sub_55C97B2014C6->sub_55C97B2012BD,可以看到程序正常运行时会打印的字符串
tea-debug
进入sub_55C97B2010B7函数,分析可知
程序对输入进行CBC模式的TEA加密,已知iv和key,密文为res
tea-debug
笔者没有CBC模式的TEA解密脚本,只能先对密文解TEA,然后按CBC模式加密思路来逆CBC
对密文解TEA:

#include <stdio.h>
#include <stdint.h>

//加密函数
void encrypt(uint32_t* v, uint32_t* k) {
	uint32_t v0 = v[0], v1 = v[1], sum = 0, i;           /* set up */
	uint32_t delta = 0x9e3779b9;                     /* a key schedule constant */
	uint32_t k0 = k[0], k1 = k[1], k2 = k[2], k3 = k[3];   /* cache key */
	for (i = 0; i < 32; i++) {                       /* basic cycle start */
		sum += delta;
		v0 += ((v1 << 4) + k0) ^ (v1 + sum) ^ ((v1 >> 5) + k1);
		v1 += ((v0 << 4) + k2) ^ (v0 + sum) ^ ((v0 >> 5) + k3);
	}                                              /* end cycle */
	v[0] = v0; v[1] = v1;
}
//解密函数
void decrypt(uint32_t* v, uint32_t* k) {
	uint32_t v0 = v[0], v1 = v[1], sum = 0xC6EF3720, i;  /* set up */
	uint32_t delta = 0x9e3779b9;                     /* a key schedule constant */
	uint32_t k0 = k[0], k1 = k[1], k2 = k[2], k3 = k[3];   /* cache key */
	for (i = 0; i<32; i++) {                         /* basic cycle start */
		v1 -= ((v0 << 4) + k2) ^ (v0 + sum) ^ ((v0 >> 5) + k3);
		v0 -= ((v1 << 4) + k0) ^ (v1 + sum) ^ ((v1 >> 5) + k1);
		sum -= delta;
	}                                              /* end cycle */
	v[0] = v0; v[1] = v1;
}

int main()
{
	uint32_t v[2] = { 0xc9fa3b95,0x7cfd0735 };//0x243a2b27,0x1d133211
	//uint32_t v[2] = { 0x958c7c9f,0xc143b59e };//0x8d945ac6,0x2393665c
	//uint32_t v[2] = { 0x61741e89,0xf47dcdc4 };//0xfbbc14c5,0x9e22f9c1
	//uint32_t v[2] = { 0xd6e2a1f2,0x6a38e9ad };//0x3e1a2ff0,0xab1ca587
	//uint32_t v[2] = { 0xc2c16feb,0x8c0ee999 };//0xb883e88a,0x683ae9d0
	uint32_t k[4] = { 0x65766967,0x756f795f,0x7075635f,0x6165745f };
	int n = sizeof(v) / sizeof(uint32_t);
	decrypt(v, k);
	for (int i = 0; i < n; i++)
	{
		printf("0x%x,", v[i]);
	}
	printf("\n");
	return 0;
}

按CBC模式加密思路来逆CBC

from Crypto.Util.number import long_to_bytes
res=[0xc9fa3b95,0x7cfd0735,0x958c7c9f,0xc143b59e,0x61741e89,0xf47dcdc4,0xd6e2a1f2,0x6a38e9ad,0xc2c16feb,0x8c0ee999]
iv=[0]*10
iv[0]=0x5f797274
iv[1]=0x64726168
for i in range(8):
    iv[i+2]=res[i]
plain=[0x243a2b27,0x1d133211,0x8d945ac6,0x2393665c,0xfbbc14c5,0x9e22f9c1,0x3e1a2ff0,0xab1ca587,0xb883e88a,0x683ae9d0]
flag=""
for i in range(10):
    flag+=long_to_bytes(plain[i]^iv[i])[::-1]
print(flag)
# SYC{ySaySanDian_Zh0n_La_y1n_Cha_xIan}
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

P1umH0

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值