目录
126_[NPUCTF2020]EzObfus-Chapter2
126_[NPUCTF2020]EzObfus-Chapter2
程序先对输入的每个字符作个处理sub_41644A()(逐字符)然后再作个逐字符的位处理,然后比对,这个符合爆破的特征
int __cdecl main(int argc, const char **argv, const char **envp)
{
int j; // [esp+18h] [ebp-10h]
int i; // [esp+1Ch] [ebp-Ch]
sub_416F80();
puts("Give Me Your Flag:\n");
scanf("%s", &Str);
if ( strlen(&Str) == 22 )
{
sub_41644A(); // str:0x426020 套函数里对(22个字符+i)^i 13-14除外
for ( i = 1; i <= 21; ++i )
{
*(&Str + i) += (dword_424080[i % 6] >> 6) ^ (16 * dword_424080[(i - 1) % 6]);
*(&Str + i) = ((int)(unsigned __int8)*(&Str + i) >> 3) | (32 * *(&Str + i));
}
for ( j = 0; j <= 21; ++j )
{
if ( *(&Str + j) != byte_424040[j] )
goto LABEL_2;
}
puts("Good Job!\n");
}
else
{
LABEL_2:
puts("Error!\n");
}
return 0;
}
这里sub_41644A()极其复杂,网上有人猜出是加序号再异或序号,但不完全对。不过可以肯定每次仅对一个字符处理时不涉及其它字符,这个就可以爆破了,先用程序patch一下比对的位数,逐位复制程序
data = list(open('attachment.exe', 'rb').read())
for i in range(22):
data[0x15a06] = i
filename = f"aaa{i}.exe"
open(filename, 'wb').write(bytes(data))
然后再逐位爆破
flag = ''
for i in range(1):
filename = f".\\aaa{i}.exe"
p = subprocess.Popen('.\\aaa0.exe', stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
print('pid', p.pid)
print('s', p.stdout.readline())
for j in range(0x21, 0x7f):
tmp = ((flag+chr(j)).ljust(22,'A')+'\n').encode()
print('tmp:', tmp)
p.stdin.write(tmp)
p.stdin.flush()
out = p.stdout.readline()
print("A:",out)
if b'Error' not in out:
flag += chr(j)
print(flag)
break
#npuctf{WDNMD_LJ_OBFU!}
127_[SUCTF2019]Akira Homework
128_[GKCTF 2021]app-debug
这是个apk文件,先用jd打开找到Resources/AndroidManifest.xml 看里边的内容<activity android:name="com.example.myapplication.MainActivity"> 这是起点
从这里找到flag打包方式
public class MainActivity extends AppCompatActivity {
......
protected void onCreate(Bundle savedInstanceState) {
......
this.mBtnLogin.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
MainActivity mainActivity = MainActivity.this;
if (mainActivity.check(mainActivity.mEtflag.getText().toString())) { //调用检查
Toast.makeText(MainActivity.this, "You Are Right!flag is flag{md5(input)}", 0).show(); //flag组装方式
} else {
Toast.makeText(MainActivity.this, "Sorry your flag is wrong!", 0).show();
}
}
});
}
}
我核对函数,这个函数在lib里lib\arm64-v8a\libnative-lib.so
用IDA打开找到对应函数
bool __fastcall Java_com_example_myapplication_MainActivity_check(__int64 a1, __int64 a2, __int64 a3)
{
...
if ( sub_40040((__int64)v6) == 7 )
{
for ( i = 0; i <= 6; ++i )
byte_C80E0[i] = *(_BYTE *)sub_40064((__int64)v6, i);
v5 = sub_3ED8C((unsigned int *)byte_C80E0); //加密函数
}
}
bool __fastcall sub_3ED8C(unsigned int *a1)
{
...
v5 = *a1;
v4 = a1[1];
v3 = 0;
for ( i = 0; i < 0x20; ++i )
{
v3 += dword_C8010;
v5 += (16 * v4 + dword_C8000) ^ (v4 + v3) ^ ((v4 >> 5) + dword_C8004);
v4 += (16 * v5 + dword_C8008) ^ (v5 + v3) ^ ((v5 >> 5) + dword_C800C);
}
*a1 = v5;
a1[1] = v4;
return *a1 == 0xF5A98FF3 && a1[1] == 0xA21873A3;
处理完运行发现不对。原来这里也用了反调,在.init_array里有函数
.init_array:00000000000C0F98 3C EF 03 00 00 00 00 00 off_C0F98 DCQ sub_3EF3C
函数对几个key 作了变更
__int64 sub_3EF3C()
{......
if ( !strcmp(s1, "0") )
sub_3EF18();
}
void sub_3EF18()
{
dword_C8004 = 7;
dword_C8008 = 8;
dword_C800C = 6;
}
根据新的key写出程序
c8010 = 0x458BCD42
c8000 = 9
c8004 = 7
c8008 = 8
c800c = 6
v3 = c8010 *0x20
v5 = 0xF5A98FF3
v4 = 0xA21873A3
for i in range(0x1f,-1,-1):
v4 -= (16 * v5 + c8008) ^ ( v5 + v3) ^ ((v5 >> 5) + c800c)
v4 &= 0xffffffff
v5 -= (16 * v4 + c8000) ^ ( v4 + v3) ^ ((v4 >> 5) + c8004)
v5 &= 0xffffffff
v3 -= c8010
v3 &= 0xffffffff
print(v5, v4,v3)
print(bytes.fromhex(hex(v5)[2:])[::-1]+bytes.fromhex(hex(v4)[2:])[::-1])
#GKcTFg0
m = b'GKcTFg0'
from hashlib import md5
print(md5(m).digest().hex())
#flag{77bca47fe645ca1bd1ac93733171c9c4}
129_[FlareOn2]YUSoMeta
打开发现是.net的程序,用dnSpy打开发现有混淆,用de4dot处理一下,再打开一个,找到main,
string text = Console.ReadLine().Trim(); //读取输入的密码
string b = Class3.smethod_0(class1_, byte_2) + '_' + Class3.smethod_3();
if (text == b)
{
Console.WriteLine(Encoding.ASCII.GetString(bytes4)); //Thank you for providing the correct password.
Console.Write(Encoding.ASCII.GetString(bytes5)); //Use the following email address to proceed to the next challenge:
Console.WriteLine(Class3.smethod_1(text, byte_));
return;
}
再回到原来没处理过的程序,在比较这个位置下断点,然后执行
执行到断点后可以看到对比的数据
metaprogrammingisherd_DD9BE1704C690FB422F1509A46ABC988
运行程序输入这个密码得到flag
C:\buuctf.reverse\129_[FlareOn2]YUSoMeta>YUSoMeta
Warning! This program is 100% tamper-proof!
Please enter the correct password: metaprogrammingisherd_DD9BE1704C690FB422F1509A46ABC988
Thank you for providing the correct password.
Use the following email address to proceed to the next challenge: Justr3adth3sourc3@flare-on.com
#flag{Justr3adth3sourc3@flare-on.com}
130_[GXYCTF2019]minecraft
ida打开后发现它处理的东西在函数String_t0_intDll里,打开dll文件(函数在dll文件中),打开主要加密逻辑
_BOOL8 __fastcall String_to_long(__int64 a1)
{
void *v2; // rax
char v3; // [rsp+30h] [rbp-138h]
int j; // [rsp+34h] [rbp-134h]
int v5; // [rsp+38h] [rbp-130h]
int i; // [rsp+3Ch] [rbp-12Ch]
_QWORD *v7; // [rsp+48h] [rbp-120h]
__int64 v8; // [rsp+50h] [rbp-118h]
_QWORD *v9; // [rsp+58h] [rbp-110h]
int v10[8]; // [rsp+60h] [rbp-108h]
char *v11; // [rsp+80h] [rbp-E8h]
const struct std::_Container_base0 *v12; // [rsp+88h] [rbp-E0h]
__int64 v13; // [rsp+90h] [rbp-D8h]
__int64 v14; // [rsp+98h] [rbp-D0h]
char *v15; // [rsp+A0h] [rbp-C8h]
const struct std::_Container_base0 *v16; // [rsp+A8h] [rbp-C0h]
char v17[32]; // [rsp+B0h] [rbp-B8h] BYREF
char v18[32]; // [rsp+D0h] [rbp-98h] BYREF
char v19[32]; // [rsp+F0h] [rbp-78h] BYREF
char v20[32]; // [rsp+110h] [rbp-58h] BYREF
char v21[32]; // [rsp+130h] [rbp-38h] BYREF
v7 = operator new(0x128ui64);
if ( v7 )
{
*v7 = 9i64;
`eh vector constructor iterator'(v7 + 1, 0x20ui64, 9ui64, sub_180003C90, (void (__stdcall *)(void *))sub_180003AF0);
v9 = v7 + 1;
}
else
{
v9 = 0i64;
}
sub_180003C90(v20);
v11 = v18;
v12 = sub_180003CE0((const struct std::_Container_base0 *)v18, a1);
v8 = sub_1800033E0(v12); // base64
if ( (unsigned __int64)unknown_libname_105(a1) >= 0xA )
{
sub_180003A60((__int64)v20, v8);
v5 = 0;
for ( i = 0; ; ++i )
{
v13 = v5;
if ( v5 >= (unsigned __int64)unknown_libname_105(v20) )
break;
v14 = sub_180003900(v20, v17, v5, 4i64);
sub_180003B20(&v9[4 * i], v14);
((void (__stdcall *)(void *))sub_180003AF0)(v17);
sub_1800039E0(&v9[4 * i], &unk_180034570);
v5 += 4; // 每4个一组分组
}
sub_180003C90(v21);
for ( j = 0; j < 8; ++j )
{
sub_180003A90(v21, &v9[4 * j]);
v15 = v19;
v16 = sub_180003CE0((const struct std::_Container_base0 *)v19, (__int64)v21);
v10[j] = sub_180003390(v16); // hash
}
v3 = 0;
v2 = (void *)sub_180004B90(&qword_18003A200, "-------Checking-----");
_CallMemberFunction0(v2, sub_180004F60);
if ( v10[0] == 0x6C43B2A7
&& v10[1] == 0x7954FD91
&& v10[2] == 0xA3E9532
&& v10[3] == 0xB87B5156
&& v10[4] == 0xDA847742
&& v10[5] == 0x2395E7F3
&& v10[6] == 0xA679D954
&& v10[7] == 0xE1FAAFF7 )
{
v3 = 1;
}
sub_180003310(v9, v8);
((void (__stdcall *)(void *))sub_180003AF0)(v21);
((void (__stdcall *)(void *))sub_180003AF0)(v20);
return v3 != 0;
}
else
{
((void (__stdcall *)(void *))sub_180003AF0)(v20);
return 0i64;
}
}
先是base64再每4个一组作个自定义的hash再比较,hash比较深
__int64 __fastcall sub_180003390(void *a1)
{
unsigned int v2; // [rsp+20h] [rbp-18h]
char v3[4]; // [rsp+24h] [rbp-14h] BYREF
v2 = unknown_libname_104(v3, a1); // hash
sub_180003AF0(a1);
return v2;
}
// Microsoft VisualC 64bit universal runtime
__int64 __fastcall unknown_libname_104(__int64 a1, __int64 a2)
{
return sub_180004B40(a2); // call hash
}
__int64 __fastcall sub_180004B40(__int64 a1)
{
__int64 *v1; // rax
__int64 *v3; // [rsp+20h] [rbp-28h]
char v4[8]; // [rsp+28h] [rbp-20h] BYREF
char v5[24]; // [rsp+30h] [rbp-18h] BYREF
v3 = (__int64 *)sub_1800059D0(a1, v4);
v1 = (__int64 *)sub_180005A30(a1, v5);
return sub_180005FB0(*v1, *v3); // call hash
}
__int64 __fastcall sub_180005FB0(__int64 a1, __int64 a2)
{
unsigned __int8 *v2; // rax
__int64 v4; // [rsp+20h] [rbp-18h] BYREF
__int64 v5; // [rsp+40h] [rbp+8h] BYREF
__int64 v6; // [rsp+48h] [rbp+10h] BYREF
v6 = a2;
v5 = a1;
v4 = 0i64;
while ( (unsigned __int8)sub_180006100(&v5, &v6) )
{
v2 = (unsigned __int8 *)unknown_libname_107(&v5);
sub_180006200(&v4, v2); // call hash
std::_String_const_iterator<std::_String_val<std::_Simple_types<char>>>::operator++(&v5);
}
return v4;
}
__int64 __fastcall sub_180006200(__int64 *a1, unsigned __int8 *a2)
{
__int64 v2; // rax
char v4[8]; // [rsp+20h] [rbp-18h] BYREF
v2 = sub_180002E00(v4, *a2);
return hash_180002D30(a1, v2);
}
__int64 __fastcall sub_180002D30(__int64 *a1, __int64 a2)
{
__int64 result; // rax
*a1 ^= 0xC6A4A7935BD1E995ui64 * (((0xC6A4A7935BD1E995ui64 * a2) >> 47) ^ (0xC6A4A7935BD1E995ui64 * a2));
*a1 *= 0xC6A4A7935BD1E995ui64;
result = *a1 + 0xE6546B64i64;
*a1 = result;
return result;
}
然后根据这个每3个字符一组进行爆破
from itertools import product
import string
from base64 import b64encode
c = [0x6C43B2A7,0x7954FD91,0xA3E9532,0xB87B5156,0xDA847742,0x2395E7F3,0xA679D954,0xE1FAAFF7]
'''
String_t0_intDll.dll sub_180002D30
*a1 ^= 0xC6A4A7935BD1E995ui64 * (((0xC6A4A7935BD1E995ui64 * a2) >> 47) ^ (0xC6A4A7935BD1E995ui64 * a2));
*a1 *= 0xC6A4A7935BD1E995ui64;
result = *a1 + 0xE6546B64i64;
*a1 = result;
'''
def hash(v):
n = b64encode(''.join(v).encode())
delta = 0xC6A4A7935BD1E995
ret = 0
for i in range(4):
ret ^= delta * ((((delta * n[i])&0xffffffffffffffff)>>47) ^ (delta * n[i]))
ret *= delta
ret += 0xE6546B64
return ret&0xffffffff
chars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ{}_-!?'
flag = ['']*8
def bp():
for v in product(chars, repeat=3): #
m = hash(v)
if m in c:
flag[c.index(m)]= ''.join(v)
print(c.index(m), v)
bp()
print(''.join(flag))
#GXY{I_have_no_gir1_frieN
#flag{I_have_no_gir1_frieNd}