天天看點

BUUCTF RE Youngter-drive

BUUCTF RE Youngter-drive

1.查殼

BUUCTF RE Youngter-drive

upx的 去kali脫殼

BUUCTF RE Youngter-drive

2.IDA

int __cdecl main_0(int argc, const char **argv, const char **envp)
{
  HANDLE v4; // [esp+D0h] [ebp-14h]
  HANDLE hObject; // [esp+DCh] [ebp-8h]

  ((void (*)(void))sub_4110FF)();
  ::hObject = CreateMutexW(0, 0, 0);
  j_strcpy(Destination, &Source);
  hObject = CreateThread(0, 0, StartAddress, 0, 0, 0);
  v4 = CreateThread(0, 0, sub_41119F, 0, 0, 0);
  CloseHandle(hObject);
  CloseHandle(v4);
  while ( dword_418008 != -1 )
    ;
  sub_411190();
  CloseHandle(::hObject);
  return 0;
}
           

可以看到建立了兩個程序

hObject = CreateThread(0, 0, StartAddress, 0, 0, 0);

v4 = CreateThread(0, 0, sub_41119F, 0, 0, 0);

檢視SrartAddress函數

void __stdcall StartAddress_0(int a1)
{
  while ( 1 )
  {
    WaitForSingleObject(hObject, 0xFFFFFFFF);
    if ( dword_418008 > -1 )
    {
      sub_41112C(&Source, dword_418008);
      --dword_418008;
      Sleep(0x64u);
    }
    ReleaseMutex(hObject);
  }
}
           

繼續跟進sub_41112c函數

char *__cdecl sub_411940(int a1, int a2)
{
  char *result; // eax
  char v3; // [esp+D3h] [ebp-5h]

  v3 = *(_BYTE *)(a2 + a1);
  if ( (v3 < 97 || v3 > 122) && (v3 < 65 || v3 > 90) )
    exit(0);
  if ( v3 < 97 || v3 > 122 )
  {
    result = off_418000[0];
    *(_BYTE *)(a2 + a1) = off_418000[0][*(char *)(a2 + a1) - 38];
  }
  else
  {
    result = off_418000[0];
    *(_BYTE *)(a2 + a1) = off_418000[0][*(char *)(a2 + a1) - 96];
  }
  return result;
}
           

97 122是國小ascii字元a-z

這就是一個判斷大小寫字元,對字元進行表替換。off_418000[0]的值為QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbn

檢視另一函數 sub_411B10(int a1)

void __stdcall sub_411B10(int a1)
{
  while ( 1 )
  {
    WaitForSingleObject(hObject, 0xFFFFFFFF);
    if ( dword_418008 > -1 )
    {
      Sleep(0x64u);
      --dword_418008;
    }
    ReleaseMutex(hObject);
  }
}
           

這裡少了對我們輸入字元的操作函數,就僅僅對dword_418008變量進行減1操作。

回到主函數最後有個sub_411190函數,打開

int sub_411880()
{
  int i; // [esp+D0h] [ebp-8h]

  for ( i = 0; i < 29; ++i )
  {
    if ( Source[i] != off_418004[i] )
      exit(0);
  }
  return printf("\nflag{%s}\n\n", Destination);
}

           

然後就可以寫腳本解題了。一開始索引dword_418008為29的時候要加密,那麼索引i為0的時候不解密,為1的時候解密。

閱讀sub_411940可以得知,我們要找到最後與Dest相比較的字元串off_418004的每一位字元在加密函數中的字元串off_418000中出現的位置,

再根據索引的奇偶,和位置+38是否大于等于65來判斷是否進行解密以及如何解密。

注意off_418004字元串隻有29位,而我們需要30位,是以最後要添加一位。(根據答案,最後一位字元解密後為’E’)

1 test = "TOiZiZtOrYaToUwPnToBsOaOapsyS"
  2 test1 = "TOiZiZtOrYaToUwPnToBsOaOapsySy" # 随便添加一位(說随便其實也不随便)
  3 key = "QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasd"
  4 Source=""
  5 for i in range(0,30):
  6     if i%2==1: # 加密
  7         # x = key.find(test[d]) # 會報錯,out of range,test隻有29位
  8         x = key.find(test1[i])
  9         if x+38 >= 65: 
 10             Source+=chr(x+38)
 11         else: 
 12             Source+=chr(x+96)
 13     else: # 不加密
 14         Source+=test1[i]
 15 print(Source)
           

flag{ThisisthreadofwindowshahaIsESE}