【為美好CTF獻(xiàn)上祝?!?New Star 2025 逆向筆記
Re
Week1
Strange Base
乍一看是個(gè)正常的 base64 加密

點(diǎn)進(jìn) base64 函數(shù)一看,看著像個(gè)正常的 base64 加密

原來(lái)是 aHello 這個(gè)數(shù)組的值跟正常 base64 的表不一樣。

只是單純的 base64 換表
表是
HElLo!A=CrQzy-B4S3|is',27h,'waITt1ng&Y0u^{/(>v<)*}GO~256789pPqWXV
掏出我們的 cyberchef

唉? 怎么解不出來(lái)啊 。
因?yàn)?y-B 會(huì)被 cyberchef 認(rèn)為是從 y 到 B
需要在 - 前頭加個(gè) \
把表?yè)Q成
HElLo!A=CrQzy\-B4S3|is'waITt1ng&Y0u^{/(>v<)*}GO~256789pPqWXVKJNMF
就行了。

X0r
簽到題,題目放 ida 后直接看到源碼
點(diǎn)擊查看代碼
int __fastcall main(int argc, const char **argv, const char **envp)
{
char Str2[32]; // [rsp+20h] [rbp-60h] BYREF
_BYTE v5[16]; // [rsp+40h] [rbp-40h]
char Str[36]; // [rsp+50h] [rbp-30h] BYREF
int v7; // [rsp+74h] [rbp-Ch]
int j; // [rsp+78h] [rbp-8h]
int i; // [rsp+7Ch] [rbp-4h]
_main();
puts("Please input your flag: ");
scanf("%25s", Str);
v7 = strlen(Str);
if ( v7 == 24 )
{
for ( i = 0; i < v7; ++i )
{
if ( i % 3 )
{
if ( i % 3 == 1 )
Str[i] ^= 0x11u;
else
Str[i] ^= 0x45u;
}
else
{
Str[i] ^= 0x14u;
}
}
v5[0] = 19;
v5[1] = 19;
v5[2] = 81;
for ( j = 0; j < v7; ++j )
Str[j] ^= v5[j % 3];
strcpy(Str2, "anu`ym7wKLl$P]v3q%D]lHpi");
if ( !strcmp(Str, Str2) )
puts("Right flag!");
else
puts("Wrong flag!");
return 0;
}
else
{
puts("Wrong flag length!");
return 0;
}
}
只是一個(gè)簡(jiǎn)單的異或加密,異或有個(gè)性質(zhì)
A ^ B ^ B =A
寫個(gè)腳本(我用的C++)求解 flag
點(diǎn)擊查看代碼
#include<bits/stdc++.h>
using namespace std;
char s[26]={"anu`ym7wKLl$P]v3q%D]lHpi"};
int v5[3];
signed main(){
for (int i=0;i<24;++i){
if ( i % 3 ){
if ( i % 3 == 1 ) s[i] ^= 0x11u;
else s[i] ^= 0x45u;
}
else s[i] ^= 0x14u;
}
v5[0] = 19;
v5[1] = 19;
v5[2] = 81;
for (int i=0;i<24;++i) {
s[i]^=v5[i%3];
cout<<s[i];
}
return 0;
}
得到 flag 為
flag{y0u_Kn0W_b4s1C_xOr}
Puzzle
ida 使用教程題,把程序放進(jìn) ida 后按照提示一步一步走即可拼湊出 flag 。
flag 分四部分 。
先 shift + F12 拿到 flag2

查一下字符串,找到 flag4

無(wú)意間看到個(gè)可疑字符串,格式上應(yīng)該是 flag1 (事實(shí)也確實(shí)是)

接下來(lái)只剩下 flag3 了
看到左邊列表有個(gè)函數(shù)名就叫 Its_about_part3()
點(diǎn)擊查看代碼
__int64 Its_about_part3()
{
__int64 result; // rax
_BYTE v1[10]; // [rsp+2Ah] [rbp-16h]
int v2; // [rsp+34h] [rbp-Ch]
int v3; // [rsp+38h] [rbp-8h]
int i; // [rsp+3Ch] [rbp-4h]
printf("You can use shift+e to extract the data.");
v3 = 8;
v2 = 8;
for ( i = 0; i < v2; ++i )
v1[i] = encrypted_array[i] ^ '\xFF\xFF\xFF\xAD';
result = v2;
v1[v2] = 0;
return result;
}
將數(shù)據(jù)異或就能得到 flag3
把他們拼起來(lái)就能得到 flag 了
EzMyDroid
安卓逆向入門題,根據(jù)題目提示,掏出我們的 jadx
把下載下來(lái)的程序放進(jìn) jadx 后,先找到咱的 Main 函數(shù)(一開(kāi)始直接搜索 flag 被詐騙了)

點(diǎn)開(kāi) FirstFragment 得到如下代碼:
點(diǎn)擊查看代碼
package work.pangbai.ezmydroid;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;
import androidx.fragment.app.Fragment;
import work.pangbai.ezmydroid.databinding.FragmentFirstBinding;
/* loaded from: classes2.dex */
public class FirstFragment extends Fragment {
private FragmentFirstBinding binding;
@Override // androidx.fragment.app.Fragment
public View onCreateView(LayoutInflater layoutInflater, ViewGroup viewGroup, Bundle bundle) {
FragmentFirstBinding fragmentFirstBindingInflate = FragmentFirstBinding.inflate(layoutInflater, viewGroup, false);
this.binding = fragmentFirstBindingInflate;
return fragmentFirstBindingInflate.getRoot();
}
@Override // androidx.fragment.app.Fragment
public void onViewCreated(View view, Bundle bundle) {
super.onViewCreated(view, bundle);
this.binding.checkFlag.setOnClickListener(new View.OnClickListener() { // from class: work.pangbai.ezmydroid.FirstFragment.1
@Override // android.view.View.OnClickListener
public void onClick(View view2) {
try {
String strEncrypt = AESECBUtils.encrypt(FirstFragment.this.binding.input.getText().toString(), "1145141919810000");
Log.i("result", strEncrypt);
if (strEncrypt.equals("cTz2pDhl8fRMfkkJXfqs2t8JBsqLkvQZDLYpWjEtkLE=")) {
Toast.makeText(FirstFragment.this.getContext(), "Right !!!", 0).show();
} else {
Toast.makeText(FirstFragment.this.getContext(), "Wrong !!!", 0).show();
}
} catch (Exception unused) {
}
}
});
}
@Override // androidx.fragment.app.Fragment
public void onDestroyView() {
super.onDestroyView();
this.binding = null;
}
}
再點(diǎn)開(kāi) AESECBUtils 函數(shù),得到如下代碼:
點(diǎn)擊查看代碼
package work.pangbai.ezmydroid;
import java.util.Base64;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
/* loaded from: classes2.dex */
public class AESECBUtils {
private static final String ALGORITHM = "AES";
private static final String TRANSFORMATION = "AES/ECB/PKCS5Padding";
public static String encrypt(String str, String str2) throws Exception {
SecretKeySpec secretKeySpec = new SecretKeySpec(str2.getBytes(), ALGORITHM);
Cipher cipher = Cipher.getInstance(TRANSFORMATION);
cipher.init(1, secretKeySpec);
return Base64.getEncoder().encodeToString(cipher.doFinal(str.getBytes("UTF-8")));
}
public static String decrypt(String str, String str2) throws Exception {
SecretKeySpec secretKeySpec = new SecretKeySpec(str2.getBytes(), ALGORITHM);
Cipher cipher = Cipher.getInstance(TRANSFORMATION);
cipher.init(2, secretKeySpec);
return new String(cipher.doFinal(Base64.getDecoder().decode(str)), "UTF-8");
}
}
不難發(fā)現(xiàn)是 AES 加密。ECB 模式 UTF-8
從 First 函數(shù)知道密鑰為
1145141919810000
密文是
cTz2pDhl8fRMfkkJXfqs2t8JBsqLkvQZDLYpWjEtkLE=
直接 AES 發(fā)現(xiàn)出不來(lái)結(jié)果,仔細(xì)檢查 AES 函數(shù)

發(fā)現(xiàn)要先給密文 base64 一下 。

得到flag
plzdebugme
這題需要在 linux 環(huán)境下動(dòng)態(tài)調(diào)試。
推薦個(gè)博客 傳送門
先把題目給出程序放到 ida 里,發(fā)現(xiàn)題目程序是個(gè)自解密程序
我們輸入內(nèi)容后,它會(huì)把密文進(jìn)行自解密,再比對(duì)自解密后的文本與我們輸入內(nèi)容對(duì)比,判斷 flag 對(duì)錯(cuò)。
既然如此,我們只要在解密完成后設(shè)個(gè)斷點(diǎn)(不設(shè)斷點(diǎn)運(yùn)行結(jié)束數(shù)據(jù)是會(huì)清空的),調(diào)試時(shí)提取數(shù)據(jù)就能提取出 flag
把斷點(diǎn)設(shè)在一切解密完成之后

然后遠(yuǎn)程調(diào)試 ,對(duì) x0r() 函數(shù)里的 flag 數(shù)組提取數(shù)據(jù) ( shift + E )
得到 flag

Week2
OhNativeEnc
這題提示我們 “安卓的 native 代碼在哪呢” 。
我們把下載下來(lái)的文件解壓后得到一個(gè) .apk 文件,放入 jadx 找到主函數(shù),再次看到提示

我們對(duì) .apk 文件進(jìn)行二次解壓 。

一路找到這個(gè) .so 文件

掏出我們逆向萬(wàn)能的 ida ,打開(kāi)這個(gè) .so 文件 。

打開(kāi) Java_work_pangbai_ohnativeenc_FirstFragment_checkFlag 這個(gè)函數(shù),找到 native
得到如下代碼
點(diǎn)擊查看代碼
char __fastcall Java_work_pangbai_ohnativeenc_FirstFragment_checkFlag(__int64 a1, __int64 a2, __int64 a3)
{
const char *v3; // rbx
unsigned int v4; // edi
unsigned int v5; // r11d
unsigned int v6; // r12d
unsigned int v7; // edx
unsigned int v8; // r14d
unsigned int v9; // r9d
unsigned int v10; // r10d
unsigned int v11; // r13d
unsigned int i; // r15d
__int64 v13; // rax
int v14; // r14d
char v15; // al
__int64 v16; // rdx
unsigned __int64 v17; // rsi
bool v18; // zf
bool v19; // cf
unsigned int v21; // [rsp+10h] [rbp-78h]
char dest[16]; // [rsp+30h] [rbp-58h] BYREF
__int128 v23; // [rsp+40h] [rbp-48h]
unsigned __int64 v24; // [rsp+50h] [rbp-38h]
v24 = __readfsqword(0x28u);
v3 = (const char *)(*(__int64 (__fastcall **)(__int64, __int64, _QWORD))(*(_QWORD *)a1 + 1352LL))(a1, a3, 0);
__android_log_print(4, "native", "input:%s", v3);
v23 = 0;
*(_OWORD *)dest = 0;
strncpy(dest, v3, 0x20u);
v4 = HIDWORD(v23);
v5 = *(_DWORD *)dest;
v6 = *(_DWORD *)&dest[4];
v7 = *(_DWORD *)&dest[12];
v8 = v23;
v9 = DWORD1(v23);
v10 = DWORD2(v23);
v11 = *(_DWORD *)&dest[8];
for ( i = 114514; i != 1488682; i += 114514 )
{
v21 = v8;
v13 = (i >> 2) & 3;
v14 = *(_DWORD *)&aThisisaxxteake[4 * v13];
v5 += (((v4 >> 5) ^ (4 * v6)) + ((v6 >> 3) ^ (16 * v4))) ^ ((i ^ v6) + (v14 ^ v4));
v6 += (((v5 >> 5) ^ (4 * v11)) + ((v11 >> 3) ^ (16 * v5)))
^ ((i ^ v11) + (v5 ^ *(_DWORD *)&aThisisaxxteake[4 * ((i >> 2) & 3 ^ 1)]));
v11 += (((v6 >> 5) ^ (4 * v7)) + ((v7 >> 3) ^ (16 * v6)))
^ ((i ^ v7) + (v6 ^ *(_DWORD *)&aThisisaxxteake[4 * ((i >> 2) & 3 ^ 2)]));
v7 += (((v11 >> 5) ^ (4 * v21)) + ((v21 >> 3) ^ (16 * v11)))
^ ((i ^ v21) + (v11 ^ *(_DWORD *)&aThisisaxxteake[4 * ((unsigned int)v13 ^ 3)]));
v8 = v21 + ((((v7 >> 5) ^ (4 * v9)) + ((v9 >> 3) ^ (16 * v7))) ^ ((i ^ v9) + (v7 ^ v14)));
v9 += (((v8 >> 5) ^ (4 * v10)) + ((v10 >> 3) ^ (16 * v8)))
^ ((i ^ v10) + (v8 ^ *(_DWORD *)&aThisisaxxteake[4 * ((i >> 2) & 3 ^ 1)]));
v10 += (((v9 >> 5) ^ (4 * v4)) + ((v4 >> 3) ^ (16 * v9)))
^ ((i ^ v4) + (v9 ^ *(_DWORD *)&aThisisaxxteake[4 * ((i >> 2) & 3 ^ 2)]));
v4 += (((v10 >> 5) ^ (4 * v5)) + ((v5 >> 3) ^ (16 * v10)))
^ ((i ^ v5) + (v10 ^ *(_DWORD *)&aThisisaxxteake[4 * ((unsigned int)v13 ^ 3)]));
}
*(_DWORD *)dest = v5;
*(_DWORD *)&dest[4] = v6;
*(_DWORD *)&dest[8] = v11;
*(_DWORD *)&dest[12] = v7;
*(_QWORD *)&v23 = __PAIR64__(v9, v8);
*((_QWORD *)&v23 + 1) = __PAIR64__(v4, v10);
v15 = 1;
if ( (_BYTE)v5 == mm[0] )
{
v16 = -1;
while ( 1 )
{
if ( dest[v16 + 2] != mm[v16 + 2] )
return v15 ^ 1;
if ( v16 == 29 )
break;
v17 = v16 + 2;
v18 = dest[v16 + 3] == mm[v16 + 3];
v16 += 2;
if ( !v18 )
{
v19 = v17 < 0x1F;
LABEL_10:
v15 = v19;
return v15 ^ 1;
}
}
v19 = 0;
goto LABEL_10;
}
return v15 ^ 1;
}
接著我們對(duì)這串代碼逆向。
(調(diào)這段逆向腳本調(diào)破防了)被學(xué)長(zhǎng)提示這是 TEA加密
cyberchef 里沒(méi) TEA ,要么上網(wǎng)找工具,要么自己寫腳本 >_<。
太菜了,拿AI寫的 python 腳本。
點(diǎn)擊查看代碼
# xxtea_variant_decrypt_fixed.py
# 題目算法:8×u32 塊,rounds=12,DELTA=114514,小端
# 關(guān)鍵修正:解密也要用 y = v[(p+1) % n]
DELTA = 114514
def to_u32s_le(b): # bytes -> [u32...]
assert len(b) % 4 == 0
return [int.from_bytes(b[i:i+4], 'little') for i in range(0, len(b), 4)]
def from_u32s_le(v): # [u32...] -> bytes
return b''.join((x & 0xFFFFFFFF).to_bytes(4, 'little') for x in v)
def xxtea_decrypt(v, k):
n = len(v) # = 8
rounds = 6 + 52 // n # = 12
sum_ = (DELTA * rounds) & 0xFFFFFFFF
v = v[:] # 不改原數(shù)組
while sum_ != 0:
e = (sum_ >> 2) & 3
for p in range(n - 1, -1, -1):
z = v[p - 1] if p > 0 else v[n - 1]
y = v[(p + 1) % n] # ★ 關(guān)鍵:用右鄰
mx = (((z >> 5) ^ ((y << 2) & 0xFFFFFFFF)) + ((y >> 3) ^ ((z << 4) & 0xFFFFFFFF))) \
^ ((sum_ ^ y) + (k[(p & 3) ^ e] ^ z))
v[p] = (v[p] - mx) & 0xFFFFFFFF
sum_ = (sum_ - DELTA) & 0xFFFFFFFF
return v
# 你的 mm(32B,按內(nèi)存順序)
mm_bytes = bytes([
0xB6,0x53,0x6E,0x4D, 0x77,0x5D,0x08,0xD2, 0xFB,0x2C,0x63,0x1E,
0xBB,0x7B,0x01,0x9B, 0xF5,0x04,0x6A,0xF4, 0x0E,0x84,0x27,0x47,
0x64,0xA1,0xE4,0xD9, 0xEF,0x12,0x44,0x37
])
# 你的 key:字符串 “ThisIsAXXteaKey” 在 rodata 里是 ASCIIZ,所以用 16 字節(jié):末尾補(bǔ) \x00
key_bytes = b"ThisIsAXXteaKey\x00"
# 解密
v = to_u32s_le(mm_bytes) # [v5,v6,v11,v7,v8,v9,v10,v4]
k = to_u32s_le(key_bytes) # 4×u32
pt = from_u32s_le(xxtea_decrypt(v, k))
print("plaintext hex:", pt.hex())
print("as ASCII:", pt.rstrip(b'\x00').decode('utf-8'))
尤皮·??怂箽v險(xiǎn)記(1)
題名是 UPX 的音譯。
先拿 UPX 脫一下殼。
在 ida 里看到主要的加密部分
點(diǎn)擊查看代碼
int __fastcall main(int argc, const char **argv, const char **envp)
{
__int64 v3; // rax
std::ostream *v4; // rax
unsigned __int64 v5; // rax
std::ostream *v6; // rax
_BYTE v8[32]; // [rsp+20h] [rbp-80h] BYREF
_BYTE v9[32]; // [rsp+40h] [rbp-60h] BYREF
_QWORD v10[4]; // [rsp+60h] [rbp-40h] BYREF
__int16 v11; // [rsp+80h] [rbp-20h]
char v12; // [rsp+86h] [rbp-1Ah]
char v13; // [rsp+87h] [rbp-19h]
__int64 v14; // [rsp+88h] [rbp-18h]
unsigned __int64 i; // [rsp+90h] [rbp-10h]
char v16; // [rsp+9Fh] [rbp-1h]
_main(argc, argv, envp);
qmemcpy(v10, "isfhGJ\tt~cU\ny\nuTjcj\tT~cj", 24);
v10[3] = 0x5047B777E756451LL;
v11 = 16753;
v14 = 34;
std::string::basic_string(v9);
std::operator<<<std::char_traits<char>>(refptr__ZSt4cout, "Enter your flag: ");
std::operator>><char>(refptr__ZSt3cin);
encrypt(v8, v9); //劃重點(diǎn)
v3 = std::string::length(v8);
if ( v14 == v3 )
{
v16 = 1;
for ( i = 0; ; ++i )
{
v5 = std::string::length(v8);
if ( i >= v5 )
break;
if ( IsDebuggerPresent() )
{
v12 = *(_BYTE *)std::string::operator[](v8, i) ^ 0xC3;
if ( v12 != *((_BYTE *)v10 + i) )
{
v16 = 0;
break;
}
}
else
{
v13 = *(_BYTE *)std::string::operator[](v8, i) ^ 0x3C;
if ( v13 != *((_BYTE *)v10 + i) )
{
v16 = 0;
break;
}
}
}
if ( v16 )
v6 = (std::ostream *)std::operator<<<std::char_traits<char>>(refptr__ZSt4cout, "Right!");
else
v6 = (std::ostream *)std::operator<<<std::char_traits<char>>(refptr__ZSt4cout, "Wrong!");
refptr__ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_(v6);
}
else
{
v4 = (std::ostream *)std::operator<<<std::char_traits<char>>(refptr__ZSt4cout, "Wrong!");
refptr__ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_(v4);
}
std::string::~string(v8);
std::string::~string(v9);
return 0;
}
__int64 __fastcall encrypt(__int64 a1, __int64 a2)
{
unsigned __int64 v2; // rax
__int64 v4; // [rsp+0h] [rbp-40h] BYREF
char v5; // [rsp+27h] [rbp-19h] BYREF
char *v6; // [rsp+28h] [rbp-18h]
char v7; // [rsp+37h] [rbp-9h]
unsigned __int64 i; // [rsp+38h] [rbp-8h]
v6 = (char *)&v4 + 39;
std::string::basic_string<std::allocator<char>>(a1, &unk_1400C7000, v6);
std::__new_allocator<char>::~__new_allocator(&v5);
for ( i = 0; ; ++i )
{
v2 = std::string::length(a2);
if ( i >= v2 )
break;
v7 = *(_BYTE *)std::string::operator[](a2, i);
if ( (unsigned int)(v7 - 48) > 9 )
{
if ( islower(v7) || isupper(v7) ) //如果是字母,鏡像轉(zhuǎn)換并切換大小寫。
std::string::operator+=(a1, (unsigned int)(char)(-69 - v7));
else
std::string::operator+=(a1, (unsigned int)v7);
}
else
{
std::string::operator+=(a1, (unsigned int)(char)(105 - v7)); //數(shù)字做鏡像轉(zhuǎn)換
}
}
return a1;
}
其中 encrypt 函數(shù)是對(duì) 字符串 a2 中的每個(gè)字節(jié)做如下變換,并把變換后的字節(jié)加到 a1 的后面:
如果該字節(jié)是數(shù)字就做 '0'->'9' , '1' -> '8' 的鏡像轉(zhuǎn)換
如果該字節(jié)是字母就做 'a'->'Z' , 'B' -> 'y' 的鏡像并切換大小寫轉(zhuǎn)換。
解密腳本如下:
點(diǎn)擊查看代碼
#include <iostream>
#include <string>
#include <cctype>
static inline char inv_encrypt(unsigned char c) {
// encrypt 的逆變換(與正變換相同,因其為自反映射)
if (std::isdigit(c)) return static_cast<char>(105 - c); // '0'..'9' 鏡像
if (std::islower(c) || std::isupper(c)) return static_cast<char>(187 - c); // 字母鏡像并互換大小寫
return static_cast<char>(c); // 其它原樣
}
int main() {
const unsigned char ct[] = {
'i','s','f','h','G','J','\t','t','~','c','U','\n','y','\n','u','T','j','c','j','\t','T','~','c','j',
'Q','d','u','~','w','{',0x04,0x05,'q','A'
};
const size_t n = sizeof(ct);
std::string flag; flag.reserve(n);
for (size_t i = 0; i < n; ++i) {
unsigned char e = ct[i] ^ 0x3C;
flag.push_back(inv_encrypt(e));
}
std::cout << flag << "\n";
return 0;
}
Look at me carefully
這題就有點(diǎn)陰間了,一個(gè)考驗(yàn)?zāi)X洞的題。
放到 ida 后看到代碼。
點(diǎn)擊查看代碼
int __cdecl main(int argc, const char **argv, const char **envp)
{
char v4; // [esp+0h] [ebp-7Ch]
char v5; // [esp+0h] [ebp-7Ch]
void *v6; // [esp+18h] [ebp-64h]
char v7[40]; // [esp+1Ch] [ebp-60h] BYREF
char v8[52]; // [esp+44h] [ebp-38h] BYREF
strcpy(v7, "cH4_1elo{ookte?0dv_}alafle___5yygume");
memset(v8, 0, 0x32u);
v6 = calloc(0x25u, 1u);
sub_401050(Format, v4);
sub_4010C0(aS, (char)v8);
if ( &v8[strlen(v8) + 1] - &v8[1] == 36 )
{
sub_4016E0(v6, v8, 27);
sub_4016E0(v6, v8, 5);
sub_4016E0(v6, v8, 6);
sub_4016E0(v6, v8, 9);
sub_4016E0(v6, v8, 28);
sub_4016E0(v6, v8, 18);
sub_4016E0(v6, v8, 32);
sub_4016E0(v6, v8, 29);
sub_4016E0(v6, v8, 4);
sub_4016E0(v6, v8, 11);
sub_4016E0(v6, v8, 15);
sub_4016E0(v6, v8, 17);
sub_4016E0(v6, v8, 22);
sub_4016E0(v6, v8, 8);
sub_4016E0(v6, v8, 34);
sub_4016E0(v6, v8, 16);
sub_4016E0(v6, v8, 19);
sub_4016E0(v6, v8, 7);
sub_4016E0(v6, v8, 26);
sub_4016E0(v6, v8, 35);
sub_4016E0(v6, v8, 2);
sub_4016E0(v6, v8, 14);
sub_4016E0(v6, v8, 21);
sub_4016E0(v6, v8, 0);
sub_4016E0(v6, v8, 1);
sub_4016E0(v6, v8, 25);
sub_4016E0(v6, v8, 13);
sub_4016E0(v6, v8, 23);
sub_4016E0(v6, v8, 20);
sub_4016E0(v6, v8, 37);
sub_4016E0(v6, v8, 30);
sub_4016E0(v6, v8, 33);
sub_4016E0(v6, v8, 10);
sub_4016E0(v6, v8, 3);
sub_4016E0(v6, v8, 12);
sub_4016E0(v6, v8, 36);
sub_4016E0(v6, v8, 24);
sub_4016E0(v6, v8, 31);
if ( sub_401880(v6, v7) )
{
sub_401050(aCongratulation, v5);
return 0;
}
else
{
sub_401050(aTryAgain, v5);
return -1;
}
}
else
{
sub_401050(aTheFlagLengthI, v5);
return -1;
}
}
一個(gè)加密函數(shù)用了三十多次。打開(kāi)加密函數(shù)后發(fā)現(xiàn)是加密套加密,看的頭皮發(fā)麻。
題目提示我們不要仔細(xì)看這些加密函數(shù)里的東西。
我們仔細(xì)看看,加密后的字符串
cH4_1elo{ookte?0dv_}alafle___5yygume
長(zhǎng)得特別像 flag 。
我們仔細(xì)觀察下這個(gè)加密函數(shù)的格式
sub_4016E0( v6 , v8 ,一個(gè) 0-37 范圍里的數(shù)字 )。
好巧不巧,加密函數(shù)執(zhí)行了 38 次,且每個(gè)數(shù)字沒(méi)有重復(fù)。換而言之,一串連續(xù)的數(shù)字都參與了加密。
cH4_1elo{ookte?0dv_}alafle___5yygume 的長(zhǎng)度正好是 38 。
大膽猜測(cè)一波,這串字符串就算打亂順序的 flag 。
c 在數(shù)組里是 a[27]
f 在數(shù)組里是 a[0]
l 在數(shù)組里是 a[1]
按照我們的猜測(cè),重新給這串字符串排下序,得到 flag
Week3
誰(shuí)改了我的密鑰啊
太陰了這題。
安卓逆向題,題目提示 “你知道so加載會(huì)執(zhí)行哪些函數(shù)嗎” 。
如果單純按照提示直接解壓 .apk 后檢查 so 文件,最后可能會(huì)在得到 flag 的前夜卡死。
先把 .apk 放到 jadx 里
源代碼-> work.pangbai -> Main
找到整個(gè)題目非常關(guān)鍵的提示:

“注意段序” 記住,要考。
然后我們按照提示,解壓 .apk ,用 ida 去打開(kāi) so 文件。
開(kāi)幕雷擊,打開(kāi) so 文件后左邊函數(shù)名提示了 SM4 加密。

Java_work_pangbai_changemykey_FirstFragment_checkFlag 這個(gè)函數(shù)是檢測(cè) flag 的函數(shù)
打開(kāi)看看。

拿到 aKey 里的內(nèi)容


浙公網(wǎng)安備 33010602011771號(hào)