扫码加圈子
获内部资料
网络安全领域各种资源,EDUSRC证书站挖掘、红蓝攻防、渗透测试等优质文章,以及工具分享、前沿信息分享、POC、EXP分享。不定期分享各种好玩的项目及好用的工具,欢迎关注。加内部圈子,文末有彩蛋(知识星球优惠卷)。
文章作者:1484321987948696
文章来源:https://xz.aliyun.com/news/18040
rust逆向,符号表也被删了,但是没管那么多,直接动调跟,看看加密逻辑在哪
__int64 sub_7FF7F63A1100()
{
unsigned __int64 flag_len; // rdx
size_t n0x41_2; // r15
void *Src_1; // r12
char *Src_4; // rdx
size_t Size; // rbx
char *v5; // r9
char *Src_2; // r8
char v7; // r11
char *Src_3; // rsi
char *v9; // rax
char n0xF0; // r8
unsigned int n0x80; // r11d
int v12; // r9d
int v13; // edi
int v14; // r11d
unsigned int n48; // esi
__int64 flag2; // r14
char v17; // bl
char *Src_6; // r11
unsigned int n32; // esi
char v20; // di
char v21; // bl
int v22; // ebx
int v23; // edi
unsigned int n22; // edi
char *Src_5; // rdx
char *Src_8; // rdi
__int64 v27; // rsi
__int64 Src_10; // rax
unsigned __int16 v29; // di
__int64 Buf1_1; // rax
_BYTE *Buf1; // rsi
__int64 i; // rax
unsigned int v33; // et0
unsigned __int8 v34; // cl
unsigned __int8 v35; // cl
_OWORD flag[4]; // [rsp+30h] [rbp-50h] BYREF
__int64 v38; // [rsp+78h] [rbp-8h] BYREF
char **_err_n_; // [rsp+80h] [rbp+0h] BYREF
void *Src; // [rsp+88h] [rbp+8h]
__int64 n8; // [rsp+90h] [rbp+10h]
__int128 v42; // [rsp+98h] [rbp+18h]
__int64 Src_7; // [rsp+B0h] [rbp+30h]
size_t Size_1; // [rsp+B8h] [rbp+38h]
int v45; // [rsp+C4h] [rbp+44h]
__int64 v46; // [rsp+C8h] [rbp+48h]
v46 = -2;
memset(flag, 0, sizeof(flag));
v38 = sub_7FF7F63A4DF0();
if ( (sub_7FF7F63A4E20(&v38, flag, 64) & 1) != 0 )// scanf
{
_err_n_ = flag_len;
sub_7FF7F63BB420(aCalledResultUn, 43, &_err_n_, &off_7FF7F63BC3A0, &off_7FF7F63BC428);// "src/main.rs"
}
if ( flag_len >= 65 ) // 长度是64?
sub_7FF7F63BB520(flag_len, 64, &off_7FF7F63BC440);// "src/main.rs"
sub_7FF7F63B47D0(&_err_n_, flag, flag_len);
n0x41_2 = _err_n_;
Src_1 = Src;
Src_4 = Src + n8;
if ( n8 )
{
Size = 0;
v5 = 0;
Src_2 = Src;
do
{
Src_3 = Src_2;
v9 = v5;
n0xF0 = *Src_2;
n0x80 = n0xF0;
if ( n0xF0 < 0 )
{
v12 = n0xF0 & 0x1F;
v13 = Src_3[1] & 0x3F;
if ( n0xF0 <= 0xDFu )
{
Src_2 = Src_3 + 2;
n0x80 = v13 | (v12 << 6);
}
else
{
v14 = (v13 << 6) | Src_3[2] & 0x3F;
if ( n0xF0 < 0xF0u )
{
Src_2 = Src_3 + 3;
n0x80 = (v12 << 12) | v14;
}
else
{
Src_2 = Src_3 + 4;
n0x80 = ((v12 & 7) << 18) | (v14 << 6) | Src_3[3] & 0x3F;
}
}
}
else
{
Src_2 = Src_3 + 1;
}
v5 = &v9[Src_2 - Src_3];
if ( n0x80 - 9 >= 5 && n0x80 != 32 )
{
if ( n0x80 < 0x80 )
goto LABEL_28;
n48 = n0x80 >> 8;
if ( n0x80 >> 8 > 0x1F )
{
if ( n48 == 32 )
{
v7 = *(off_7FF7F63C6078 + n0x80) >> 1;
}
else
{
if ( n48 != 48 )
goto LABEL_28;
v7 = n0x80 == 12288;
}
}
else if ( n48 )
{
if ( n48 != 22 )
goto LABEL_28;
v7 = n0x80 == 5760;
}
else
{
v7 = *(off_7FF7F63C6078 + n0x80);
}
if ( (v7 & 1) == 0 )
goto LABEL_28;
}
}
while ( Src_2 != Src_4 );
flag2 = 1;
LOBYTE(v9) = 1;
v45 = v9;
LABEL_60:
Src_5 = Src;
goto LABEL_61;
}
v9 = 0;
v5 = 0;
Src_2 = Src;
LABEL_28:
if ( Src_2 == Src_4 )
{
LABEL_53:
if ( n8 )
{
Size = v5 - v9;
if ( v5 - v9 < 0 )
goto LABEL_74;
goto LABEL_55;
}
flag2 = 1;
LOBYTE(v9) = 1;
v45 = v9;
Size = 0;
goto LABEL_60;
}
while ( 1 )
{
Src_6 = Src_4;
n32 = *(Src_4 - 1);
if ( (n32 & 0x80000000) != 0 )
break;
--Src_4;
if ( n32 - 9 >= 5 )
goto LABEL_43;
LABEL_32:
if ( Src_2 == Src_4 )
goto LABEL_53;
}
v20 = *(Src_4 - 2);
if ( v20 >= -64 )
{
Src_4 -= 2;
v23 = v20 & 0x1F;
}
else
{
v21 = *(Src_4 - 3);
if ( v21 >= -64 )
{
Src_4 -= 3;
v22 = v21 & 0xF;
}
else
{
Src_4 -= 4;
v22 = ((*(Src_6 - 4) & 7) << 6) | v21 & 0x3F;
}
v23 = (v22 << 6) | v20 & 0x3F;
}
n32 = (v23 << 6) | n32 & 0x3F;
if ( n32 - 9 < 5 )
goto LABEL_32;
LABEL_43:
if ( n32 == 32 )
goto LABEL_32;
if ( n32 < 0x80 )
goto LABEL_73;
n22 = n32 >> 8;
if ( n32 >> 8 <= 0x1F )
{
if ( n22 )
{
if ( n22 != 22 )
goto LABEL_73;
v17 = n32 == 5760;
}
else
{
v17 = *(off_7FF7F63C6078 + n32);
}
goto LABEL_31;
}
if ( n22 == 32 )
{
v17 = *(off_7FF7F63C6078 + n32) >> 1;
goto LABEL_31;
}
if ( n22 == 48 )
{
v17 = n32 == 12288;
LABEL_31:
if ( (v17 & 1) == 0 )
goto LABEL_73;
goto LABEL_32;
}
LABEL_73:
v5 = &Src_6[v5 - Src_2];
Size = v5 - v9;
if ( v5 - v9 < 0 )
{
LABEL_74:
v27 = 0;
LABEL_75:
Src_7 = Src_1;
Size_1 = n0x41_2;
sub_7FF7F63BAFA0(v27, Size);
}
LABEL_55:
Src_5 = &v9[Src];
if ( v5 == v9 )
{
flag2 = 1;
LOBYTE(v9) = 1;
v45 = v9;
}
else
{
Src_8 = &v9[Src];
v27 = 1;
Src_10 = sub_7FF7F63A17D0(Size, 1);
if ( !Src_10 )
goto LABEL_75;
flag2 = Src_10;
v45 = 0;
Src_5 = Src_8;
}
LABEL_61:
memcpy(flag2, Src_5, Size);
if ( 2 * n0x41_2 )
sub_7FF7F63A17E0(Src_1, n0x41_2, 1);
Size_1 = Size;
Src_7 = flag2;
if ( Size == 1 )
sub_7FF7F63BB200(1, 1, &off_7FF7F63BC410); // "src/main.rs"
if ( !Size )
sub_7FF7F63BB200(0, 0, &off_7FF7F63BC3F8); // "src/main.rs"
v29 = *flag2;
Buf1_1 = sub_7FF7F63A1800(Size, 1);
if ( !Buf1_1 )
sub_7FF7F63BAFA0(1, Size);
Buf1 = Buf1_1;
for ( i = 0; i != Size; ++i )
{
HIWORD(v33) = (v29 >> 2) ^ (v29 >> 3) ^ (v29 >> 1);
LOWORD(v33) = v29;
v29 = v33 >> 1;
v34 = __ROL1__(v33, 4);
v35 = (4 * (v34 & 0x33)) | (v34 >> 2) & 0x33;
Buf1[i] = *(flag2 + i) ^ (i + ((2 * (v35 & 0x55)) | (v35 >> 1) & 0x55));
}
if ( Size == 42 && !memcmp(Buf1, &enc, 42u) )
{
sub_7FF7F63A17E0(Buf1, 42, 1);
_err_n_ = &off_7FF7F63BC4A0;
Src = 1;
n8 = 8;
v42 = 0;
sub_7FF7F63A5750(&_err_n_);
}
else
{
sub_7FF7F63A17E0(Buf1, Size, 1);
_err_n_ = &off_7FF7F63BC488; // "errn"
Src = 1;
n8 = 8;
v42 = 0;
sub_7FF7F63A5750(&_err_n_);
}
return sub_7FF7F63A17E0(Src_7, Size_1, 1);
}
加密逻辑如下
v29 = *flag2;
Buf1_1 = sub_7FF7F63A1800(Size, 1);
if ( !Buf1_1 )
sub_7FF7F63BAFA0(1, Size);
Buf1 = Buf1_1;
for ( i = 0; i != Size; ++i )
{
HIWORD(v33) = (v29 >> 2) ^ (v29 >> 3) ^ (v29 >> 1);
LOWORD(v33) = v29;
v29 = v33 >> 1;
v34 = __ROL1__(v33, 4);
v35 = (4 * (v34 & 0x33)) | (v34 >> 2) & 0x33;
Buf1[i] = *(flag2 + i) ^ (i + ((2 * (v35 & 0x55)) | (v35 >> 1) & 0x55));
}
就对于密文来说就是一个异或而已,但是与之异或的密钥流是和输入的前两个明文有关,也就是上面的v29,然后就可以直接仿写此密钥流的生成逻辑,拿到异或的值,当然也可以动调跟,拿到v35的值,再进行最后一步的生成,最后异或解密也可以
脚本如下
enc = [ 0x00, 0xA1, 0xFB, 0x53, 0x1C, 0xFA, 0xF0, 0x1B, 0x06, 0x40, 0xD4, 0x8C, 0x16, 0xF4, 0x90, 0x27,
0x42, 0xB9, 0x8B, 0x0F, 0x02, 0xD7, 0x31, 0xB7, 0x26, 0x12, 0x06, 0x7E, 0xAE, 0xDF, 0xDA, 0x68,
0xAF, 0x35, 0xCC, 0xB7, 0xB0, 0xD0, 0x9A, 0x59, 0x2B, 0x0B]
v29 = 0x66 + (0x6c << 8)
box = [0] * 42
for i in range(42):
h = ((v29 >> 2) ^ (v29 >> 3) ^ (v29 >> 1)) & 0xffff
l = v29 & 0xffff
hl = (h << 16) | l
v29 = (hl >> 1) & 0xffff
v34 = (((hl & 0xFF) << 4) | ((hl & 0xFF) >> 4)) & 0xFF
v35 = ((4 * (v34 & 0x33)) | (v34 >> 2) & 0x33) & 0xff
box[i] = (i + ((2 * (v35 & 0x55)) | (v35 >> 1) & 0x55)) & 0xff
for i in range(42):
print(chr((enc[i] ^ box[i]) & 0xff), end="")
flag{1c98572d-7f7b-4fbf-8750-4a2986c695ce}
如题,就是SIMD
主函数如下
int __fastcall main(int argc, const char **argv, const char **envp)
{
Stream *Stream; // rax
size_t n0x40; // rax
__int64 n32; // rax
unsigned __int64 n0x20; // rax
__m128i v8; // xmm2
__m128i v9; // xmm1
char Buffer[16]; // [rsp+20h] [rbp-58h] BYREF
__int128 v11; // [rsp+30h] [rbp-48h]
__int128 v12; // [rsp+40h] [rbp-38h]
__int128 v13; // [rsp+50h] [rbp-28h]
sub_140001010("Enter flag: ");
Stream = _acrt_iob_func(0);
fgets(Buffer, 64, Stream);
n0x40 = strcspn(Buffer, "n");
if ( n0x40 >= 0x40 )
_report_rangecheckfailure();
Buffer[n0x40] = 0;
n32 = -1i64;
do
++n32;
while ( Buffer[n32] );
if ( n32 == 32 )
{
n0x20 = 0i64;
v8 = _mm_loadu_si128((const __m128i *)&xmmword_1400032F8);
xmmword_140005630 = v11;
xmmword_140005620 = *(_OWORD *)Buffer;
xmmword_140005650 = v13;
v9 = _mm_loadu_si128((const __m128i *)&xmmword_1400032E8);
xmmword_140005640 = v12;
do
{
*(__m128i *)&Buffer[n0x20] = _mm_add_epi8(
_mm_shuffle_epi8(_mm_loadu_si128((const __m128i *)&Buffer[n0x20]), v8),
v9);
n0x20 += 16i64;
}
while ( n0x20 < 0x20 );
if ( !memcmp(Buffer, "cge87k?9<>?@=pss393=>;8@:Cp@DAuH", 0x20ui64) )
sub_140001010("Correct! The flag is flag{%s}n");
else
puts("Wrong!");
return 0;
}
else
{
puts("Wrong!");
return 1;
}
}
就是两个指令_mm_add_epi8和_mm_shuffle_epi8,不是很熟悉,先去网上查了下,add没什么好说的,就是相加,shuffle,是以第二个参数的值作为索引,去第一个参数中取值,取到的值即为打乱后的密文,但是这里要注意,再传参的时候是小端序,不然就这题来说,打乱前和打乱后就没什么区别了
解密脚本如下
encrypted_flag1 = "cge87k?9<>?@=pss"
encrypte_flag1 = encrypted_flag1[::-1]
enc1 = list(encrypte_flag1)
v9 = [0x10, 0x0F, 0x0E, 0x0D, 0x0C, 0x0B, 0x0A, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01]
v8 = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F]
for i in range(len(enc1)):
print(chr(ord(enc1[i]) - v9[i % 16]), end="")
encrypted_flag2 = "393=>;8@:Cp@DAuH"
encrypte_flag2 = encrypted_flag2[::-1]
enc2 = list(encrypte_flag2)
v9 = [0x10, 0x0F, 0x0E, 0x0D, 0x0C, 0x0B, 0x0A, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01]
v8 = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F]
for i in range(len(enc2)):
print(chr(ord(enc2[i]) - v9[i % 16]), end="")
flag{cdb0444318e24beb8f374e9181599072}
iso逆向。
一开始想跟字符串,倒着跟踪到main函数,但是发现确实跟到了,但是有点抽象。于是乎,只能从头开始分析,也就是从初始化函数开始
ViewController.init
id __fastcall ViewController.init(nibName:bundle:)(__int64 a1, __int64 a2, void *obj_1)
{
char *receiver; // x20
char *v5; // x8
char *v6; // x8
NSString obj; // x21
id v9; // x20
objc_super v11; // [xsp+0h] [xbp-30h] BYREF
v5 = &receiver[OBJC_IVAR____TtC9challenge14ViewController_secretKey];
*(_QWORD *)v5 = 'akihuraH';
*((_QWORD *)v5 + 1) = 0xEA00000000006567LL;
v6 = &receiver[OBJC_IVAR____TtC9challenge14ViewController_flagHash];
*(_QWORD *)v6 = 0xD000000000000126LL;
*((_QWORD *)v6 + 1) = 0x8000000100003C20LL;
*(_QWORD *)&receiver[OBJC_IVAR____TtC9challenge14ViewController_magicNumber] = 3735928559LL;
*(_QWORD *)&receiver[OBJC_IVAR____TtC9challenge14ViewController_inputTextField] = 0;
*(_QWORD *)&receiver[OBJC_IVAR____TtC9challenge14ViewController_outputTextField] = 0;
*(_QWORD *)&receiver[OBJC_IVAR____TtC9challenge14ViewController_encryptButton] = 0;
if ( a2 )
{
obj = String._bridgeToObjectiveC()();
a1 = swift_bridgeObjectRelease(a2);
}
else
{
obj = 0;
}
v11.receiver = receiver;
v11.super_class = (Class)type metadata accessor for ViewController(a1);
v9 = objc_msgSendSuper2(&v11, "initWithNibName:bundle:", obj, obj_1);
objc_release(obj);
objc_release(obj_1);
return v9;
}
这里有看到一个初始化的key:Haruhikage。(这里要注意,伪代码中的key不完整,还差两位...)
然后就开始分析ViewController.encryptButtonClicked()
这里就是check输出正确flag的地方
在String里找这个这个提示的时候还看到了一个可疑的字符串
c2..c3..。都是以这样的形式。
然后分析这个函数下来,主要逻辑就是获取到输入的flag,先检查是否为空,不为空的话就传到ViewController.complexEncrypt(_:)函数中进行加密,然后在ViewController.verifyFlag(_:)函数中进行check。
加密函数
__int64 __fastcall ViewController.complexEncrypt(_:)(__int64 a1, __int64 a2)
{
__int64 v2; // x20
__int64 v5; // x22
__int64 v6; // x24
char *v7; // x23
__int64 v8; // x19
__int64 v9; // x1
__int64 v10; // x21
__int64 v11; // x19
unsigned __int64 v12; // x1
unsigned __int64 v13; // x20
__int64 _countAndFlagsBits; // x0
void *_object; // x21
Swift::String v16; // kr00_16
__int64 v17; // x19
__int64 v18; // x1
__int64 v19; // x20
__int64 v20; // x19
__int64 v22; // [xsp+0h] [xbp-30h] BYREF
v5 = type metadata accessor for String.Encoding(0);
v6 = *(v5 - 8);
v7 = &v22 - ((*(v6 + 64) + 15LL) & 0xFFFFFFFFFFFFFFF0LL);
v8 = specialized ViewController.rc4Encrypt(_:key:)(// RC4
a1,
a2,
*(v2 + OBJC_IVAR____TtC9challenge14ViewController_secretKey),
*(v2 + OBJC_IVAR____TtC9challenge14ViewController_secretKey + 8));
v10 = v9;
static String.Encoding.utf8.getter(); // UTF8
v11 = String.data(using:allowLossyConversion:)(v7, 0, v8, v10);
v13 = v12;
swift_bridgeObjectRelease(v10);
(*(v6 + 8))(v7, v5);
if ( v13 >> 60 == 15 )
{
_countAndFlagsBits = 0;
_object = 0xE000000000000000LL;
}
else
{
v16 = Data.base64EncodedString(options:)(0);// base64
_object = v16._object;
outlined consume of Data?(v11, v13);
_countAndFlagsBits = v16._countAndFlagsBits;
}
v17 = specialized ViewController.obfuscateString(_:)(_countAndFlagsBits, _object);// obfuscateString
v19 = v18;
swift_bridgeObjectRelease(_object);
v20 = specialized ViewController.transformString(_:)(v17, v19);// transformString
swift_bridgeObjectRelease(v19);
return v20;
}
整体的加密逻辑就是RC4->base64->obfuscateString->transformString
transformString函数,有点抽象
void *__fastcall specialized ViewController.transformString(_:)(__int64 a1, unsigned __int64 a2)
{
unsigned __int64 v2; // x8
void *_countAndFlagsBits; // x0
Swift::String_optional v4; // kr00_16
void *_object; // x19
__int64 index; // x21
__int64 v7; // x20
unsigned int n190; // w8
unsigned int v9; // w8
Swift::String v10; // x0
void *_object_1; // x19
Swift::String_optional v12; // kr10_16
int v13; // w10
int v14; // w9
int v15; // w10
int v16; // w13
int v17; // w10
_QWORD v18[2]; // [xsp+8h] [xbp-88h] BYREF
unsigned __int64 v19; // [xsp+18h] [xbp-78h]
__int64 v20; // [xsp+20h] [xbp-70h]
unsigned __int64 v21; // [xsp+28h] [xbp-68h]
void *_object_2; // [xsp+30h] [xbp-60h]
unsigned __int64 v23; // [xsp+38h] [xbp-58h]
_object_2 = 0;
v23 = 0xE000000000000000LL;
v2 = HIBYTE(a2) & 0xF;
if ( (a2 & 0x2000000000000000LL) == 0 )
v2 = a1 & 0xFFFFFFFFFFFFLL;
v18[1] = a1;
v19 = a2;
v20 = 0;
v21 = v2;
swift_bridgeObjectRetain(a2);
v4 = String.Iterator.next()(); // 获取字符串迭代器
_countAndFlagsBits = v4.value._countAndFlagsBits;
_object = v4.value._object;
if ( v4.value._object )
{
index = 0;
while ( !__OFADD__(index, 1) ) // 遍历每个字符
{
v7 = specialized Collection.first.getter(_countAndFlagsBits, _object);// 获取当前字符
_countAndFlagsBits = swift_bridgeObjectRelease(_object);
if ( (index & 1) != 0 ) // 判断奇偶
// 奇数异或 0xBE
// 偶数异或 0xEF
{
n190 = v7 ^ 0xBE;
if ( (v7 & &_mh_execute_header) != 0 )
n190 = 190;
if ( n190 >> 11 == 27 )
goto LABEL_30;
if ( n190 > 0x10FFFF )
goto LABEL_27;
}
else
{
n190 = v7 ^ 0xEF;
if ( (v7 & &_mh_execute_header) != 0 )
n190 = 239;
if ( n190 >> 11 == 27 )
goto LABEL_29;
if ( n190 > 0x10FFFF )
goto LABEL_28;
}
if ( n190 > 0x7F )
{
v13 = (n190 & 0x3F) << 8;
v14 = (n190 >> 6) + v13 + 33217;
v15 = (v13 | (n190 >> 6) & 0x3F) << 8;
v16 = (n190 >> 18) + ((v15 | (n190 >> 12) & 0x3F) << 8) - 2122219023;
v17 = (n190 >> 12) + v15 + 8487393;
if ( HIWORD(n190) )
v17 = v16;
if ( n190 >= 0x800 )
v9 = v17;
else
v9 = v14;
}
else
{
v9 = n190 + 1;
}
v18[0] = (v9 + 0xFEFEFEFEFEFEFFLL) & ~(-1LL << (8 * (4 - (__clz(v9) >> 3))));
v10._countAndFlagsBits = static String._uncheckedFromUTF8(_:)(v18);
_object_1 = v10._object;
String.append(_:)(v10);
swift_bridgeObjectRelease(_object_1);
v12 = String.Iterator.next()(); // 移动到下一个字符
_countAndFlagsBits = v12.value._countAndFlagsBits;
_object = v12.value._object; // 检查是否结束
++index;
if ( !v12.value._object )
{
_object = _object_2;
goto LABEL_25;
}
}
__break(1u);
LABEL_27:
__break(1u);
LABEL_28:
__break(1u);
LABEL_29:
__break(1u);
LABEL_30:
__break(1u);
}
else
{
LABEL_25:
swift_bridgeObjectRelease(v19);
return _object;
}
return _countAndFlagsBits;
}
总的来说就是一个异或,但是在异或完,有个奇怪的逻辑
可以按照这个逻辑来仿写一个看看输出是什么。这里还要查下__clz()有什么用
同构的脚本:
def __clz(x):
return 64 - x.bit_length() if x != 0 else 64
for n190 in range(0x00, 0x100): # 0x00到0xFF
# 处理非ASCII字符(>0x7F)
if n190 > 0x7F:
v13 = (n190 & 0x3F) << 8
v14 = (n190 >> 6) + v13 + 33217
v15 = (v13 | ((n190 >> 6) & 0x3F)) << 8
v16 = (n190 >> 18) + ((v15 | ((n190 >> 12) & 0x3F)) << 8) - 2122219023
v17 = (n190 >> 12) + v15 + 8487393
if n190 > 0xFFFF:
v17 = v16
v9 = v17 if n190 >= 0x800 else v14
else:
v9 = n190 + 1
# 安全计算移位量(确保非负)
shift = 8 * (4 - (__clz(v9) >> 3))
shift = max(0, min(shift, 64)) # 限制在0-64范围内
# 计算掩码
mask = ~(-1 << shift) if shift > 0 else 0xFFFFFFFFFFFFFFFF
v9 = (v9 + 0xFEFEFEFEFEFEFF) & mask
print(f"{hex(n190)} -> {hex(v9)}")
这样一来就知道了那串可疑字符串中c2,c3的来处了。以及如果是c3开头的,在解密的时候要-0x40.
obfuscateString函数
void *__fastcall specialized ViewController.obfuscateString(_:)(__int64 _countAndFlagsBits, unsigned __int64 _object)
{
unsigned __int64 v2; // x8
void *_countAndFlagsBits_1; // x0
Swift::String_optional v4; // kr00_16
void *_object_2; // x19
__int64 v6; // x21
__int64 v7; // x20
__int64 v8; // x8
bool v9; // vf
__int64 v10; // x8
__int64 v11; // x8
bool v12; // nf
unsigned int v13; // w8
Swift::String v14; // x0
void *_object_3; // x19
Swift::String_optional v16; // kr10_16
_QWORD v17[2]; // [xsp+8h] [xbp-78h] BYREF
unsigned __int64 _object_1; // [xsp+18h] [xbp-68h]
__int64 v19; // [xsp+20h] [xbp-60h]
unsigned __int64 v20; // [xsp+28h] [xbp-58h]
void *_object_4; // [xsp+30h] [xbp-50h]
unsigned __int64 v22; // [xsp+38h] [xbp-48h]
_object_4 = 0;
v22 = 0xE000000000000000LL;
v2 = HIBYTE(_object) & 0xF;
if ( (_object & 0x2000000000000000LL) == 0 )
v2 = _countAndFlagsBits & 0xFFFFFFFFFFFFLL;
v17[1] = _countAndFlagsBits;
_object_1 = _object;
v19 = 0;
v20 = v2;
swift_bridgeObjectRetain(_object);
v4 = String.Iterator.next()();
_countAndFlagsBits_1 = v4.value._countAndFlagsBits;
_object_2 = v4.value._object;
if ( v4.value._object )
{
v6 = 0;
while ( !__OFADD__(v6, 1) )
{
v7 = specialized Collection.first.getter(_countAndFlagsBits_1, _object_2);
_countAndFlagsBits_1 = swift_bridgeObjectRelease(_object_2);
v8 = v7;
if ( (v7 & &_mh_execute_header) != 0 )
v8 = 0;
v9 = __OFADD__(v8, v6);
v10 = v8 + v6;
if ( v9 )
goto LABEL_20;
v9 = __OFADD__(v10, 3735928559LL);
v11 = v10 + 3735928559LL;
if ( v9 )
goto LABEL_21;
v12 = -v11 < 0;
v11 = v11;
if ( !v12 )
v11 = --v11;
if ( v11 < 0 )
goto LABEL_22;
if ( (v11 & 0xFFFFFF80) != 0 )
v13 = (((v11 & 0x3F) << 8) | (v11 >> 6)) + 33217;
else
v13 = v11 + 1;
v17[0] = (v13 + 0xFEFEFEFEFEFEFFLL) & ~(-1LL << (8 * (4 - (__clz(v13) >> 3))));
v14._countAndFlagsBits = static String._uncheckedFromUTF8(_:)(v17);
_object_3 = v14._object;
String.append(_:)(v14);
swift_bridgeObjectRelease(_object_3);
v16 = String.Iterator.next()();
_countAndFlagsBits_1 = v16.value._countAndFlagsBits;
_object_2 = v16.value._object;
++v6;
if ( !v16.value._object )
{
_object_2 = _object_4;
goto LABEL_18;
}
}
__break(1u);
LABEL_20:
__break(1u);
LABEL_21:
__break(1u);
LABEL_22:
__break(1u);
}
else
{
LABEL_18:
swift_bridgeObjectRelease(_object_1);
return _object_2;
}
return _countAndFlagsBits_1;
}
加密逻辑:+索引index和常数0xDEADBEEF,然后&0xFF
那么就可以解密了
hex_enc = "c2a7c3b9c2acc3a5c2a2c3b6c391c295c2aac38cc28bc38ac2a6c3aec28bc28fc2a1c3aac287c382c2bfc3b6c282c38ec2b9c3a2c2a13cc28ac3adc2b1c280c2b2c384c28dc3bbc283c396c2b03dc28a3bc2b12cc287c3b0c2852bc282c39ac28432c29320c29d21c29ac392c291c3a1c296c3a06d1866396c256310c299c3946931c291c3917a2e470b632a7811730f65c385"
def de_utf(hex_str):
res = bytearray()
i = 0
while i < len(hex_str):
prefix = hex_str[i:i+2]
if prefix == "c2":
val = int(hex_str[i+2:i+4], 16)
res.append(val)
i += 4
elif prefix == "c3":
val = int(hex_str[i+2:i+4], 16) + 0x40
res.append(val)
i += 4
else:
val = int(prefix, 16)
res.append(val)
i += 2
return res
step1 = de_utf(hex_enc)
for i in range(len(step1)):
step1[i] ^= 0xBE if i % 2 else 0xEF
step2 = de_utf(step1.hex())
for i in range(len(step2)):
step2[i] = (step2[i] - i - 0xDEADBEEF) & 0xFF
print(step2.decode(errors="ignore"))
解得
YWRiZTI5NzkzNTg3OTgzMDhjOTExZGQ0NjQ3YTJmNmExM2MwNDJjYzMyNDU5N2UxZWRiYzA4OWE5ZTkwMTVmYmE5
flag{N4nd3_H4ruhik4g3_Y4tt4n0?!!}
原文始发于微信公众号(神农Sec):京麒CTF2025 热身赛 RE
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论