[buuctf.reverse] 126-130

目录

126_[NPUCTF2020]EzObfus-Chapter2

128_[GKCTF 2021]app-debug

129_[FlareOn2]YUSoMeta

130_[GXYCTF2019]minecraft


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}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值