10月buu刷题re部分笔记

发布于 2020-10-06  2553 次阅读


buu-SimpleRev

unsigned __int64 Decry()
{
  char cChar; // [rsp+Fh] [rbp-51h]
  int v2; // [rsp+10h] [rbp-50h]
  int v3; // [rsp+14h] [rbp-4Ch]
  int i; // [rsp+18h] [rbp-48h]
  int keyLength; // [rsp+1Ch] [rbp-44h]
  char src[8]; // [rsp+20h] [rbp-40h]
  __int64 v7; // [rsp+28h] [rbp-38h]
  int v8; // [rsp+30h] [rbp-30h]
  __int64 v9; // [rsp+40h] [rbp-20h]
  __int64 v10; // [rsp+48h] [rbp-18h]
  int v11; // [rsp+50h] [rbp-10h]
  unsigned __int64 v12; // [rsp+58h] [rbp-8h]

  v12 = __readfsqword(0x28u);
  *(_QWORD *)src = 'SLCDN';
  v7 = 0LL;
  v8 = 0;
  v9 = 'wodah';
  v10 = 0LL;
  v11 = 0;
  text = join(key3, (const char *)&v9);         // killshadow
  strcpy(key, key1);
  strcat(key, src);                             // ADSFKNDCLS
  v2 = 0;
  v3 = 0;
  getchar();
  keyLength = strlen(key);
  for ( i = 0; i < keyLength; ++i )
  {
    if ( key[v3 % keyLength] > '@' && key[v3 % keyLength] <= 'Z' )
      key[i] = key[v3 % keyLength] + 32;
    ++v3;
  }
  printf("Please input your flag:", src);
  while ( 1 )
  {
    cChar = getchar();
    if ( cChar == '\n' )
      break;
    if ( cChar == ' ' )
    {
      ++v2;
    }
    else
    {
      if ( cChar <= '`' || cChar > 'z' )        // 不属于a-z的范围
      {
        if ( cChar > '@' && cChar <= 'Z' )      // 如果出现大写字母
          str2[v2] = (cChar - 39 - key[v3++ % keyLength] + 'a') % 26 + 'a';
      }
      else
      {
        str2[v2] = (cChar - 39 - key[v3++ % keyLength] + 'a') % 26 + 'a';
      }
      if ( !(v3 % keyLength) )
        putchar(' ');
      ++v2;
    }
  }
  if ( !strcmp(text, str2) )
    puts("Congratulation!\n");
  else
    puts("Try again!\n");
  return __readfsqword(0x28u) ^ v12;
}

这里需要注意大小端存储的问题。例如src由于是小端存储的,因此需要倒过来。其他的顺着原来的代码分析逆向即可。exp中flag的每一位都进行枚举判断即可。

key = list("adsfkndcls")
text = list("killshadow")
ll="ABCDEFGHIJKLMNOPQRSTUVWXYZ"
a=0
flag=''
while(a<len(text)):
    for i in ll:
        if((ord(i)-39-ord(key[a])+ord('a'))%26+ord('a')==ord(text[a])):
            flag+=i
            a+=1
            break
print(flag)

buuoj CrackRTF

int main_0()
{
  DWORD v0; // eax
  DWORD StringLen; // eax
  CHAR String; // [esp+4Ch] [ebp-310h]
  int v4; // [esp+150h] [ebp-20Ch]
  CHAR String1; // [esp+154h] [ebp-208h]
  BYTE pbData; // [esp+258h] [ebp-104h]

  memset(&pbData, 0, 0x104u);
  memset(&String1, 0, 0x104u);
  v4 = 0;
  printf("pls input the first passwd(1): ");
  scanf("%s", &pbData);
  if ( strlen((const char *)&pbData) != 6 )     // pbData=123321
  {
    printf("Must be 6 characters!\n");
    ExitProcess(0);
  }
  v4 = atoi((const char *)&pbData);
  if ( v4 < 100000 )
    ExitProcess(0);
  strcat((char *)&pbData, "@DBApp");            // pbData=123321@DBApp
  v0 = strlen((const char *)&pbData);
  sub_40100A(&pbData, v0, &String1);
  if ( !_strcmpi(&String1, "6E32D0943418C2C33385BC35A1470250DD8923A9") )// String1 = 6E32D0943418C2C33385BC35A1470250DD8923A9 (sha1)
  {
    printf("continue...\n\n");
    printf("pls input the first passwd(2): ");
    memset(&String, 0, '\x01\x04');
    scanf("%s", &String);
    if ( strlen(&String) != 6 )
    {
      printf("Must be 6 characters!\n");        // String : Pwd Target
      ExitProcess(0);
    }
    strcat(&String, (const char *)&pbData);     // String = Pwd+'123321@DBApp'
    memset(&String1, 0, 0404u);
    StringLen = strlen(&String);
    sub_401019((BYTE *)&String, StringLen, &String1);// calc md5 val(String) -> String1
    if ( !_strcmpi("27019e688a4e62a649fd99cadaafdb4e", &String1) )
    {
      if ( !sub_40100F(&String) )
      {
        printf("Error!!\n");
        ExitProcess(0);
      }
      printf("bye ~~\n");
    }
  }
  return 0;
}

要求两个密码,第一个字符串有40位。先进入sub_401230看看,传入的String参数是第二组的密码+"123321@DBApp"的值,继续分析:

int __cdecl sub_401230(BYTE *pbData, DWORD dwDataLen, LPSTR lpString1)
{
  int result; // eax
  DWORD i; // [esp+4Ch] [ebp-28h]
  CHAR String2; // [esp+50h] [ebp-24h]
  BYTE v6[20]; // [esp+54h] [ebp-20h]
  DWORD pdwDataLen; // [esp+68h] [ebp-Ch]
  HCRYPTHASH phHash; // [esp+6Ch] [ebp-8h]
  HCRYPTPROV phProv; // [esp+70h] [ebp-4h]

  if ( !CryptAcquireContextA(&phProv, 0, 0, 1u, 0xF0000000) )
    return 0;
  if ( CryptCreateHash(phProv, 0x8004u, 0, 0, &phHash) )
  {
    if ( CryptHashData(phHash, pbData, dwDataLen, 0) )
    {
      CryptGetHashParam(phHash, 2u, v6, &pdwDataLen, 0);
      *lpString1 = 0;
      for ( i = 0; i < pdwDataLen; ++i )
      {
        wsprintfA(&String2, "%02X", v6[i]);
        lstrcatA(lpString1, &String2);
      }
      CryptDestroyHash(phHash);
      CryptReleaseContext(phProv, 0);
      result = 1;
    }
    else
    {
      CryptDestroyHash(phHash);
      CryptReleaseContext(phProv, 0);
      result = 0;
    }
  }
  else
  {
    CryptReleaseContext(phProv, 0);
    result = 0;
  }
  return result;
}

可以看到是一堆内置好的加密函数,其中CryptCreateHash函数的第二个参数是0x8004,找到官方文档,是sha1。

https://docs.microsoft.com/en-us/windows/win32/seccrypto/alg-id

由此可以推断,6E32D0943418C2C33385BC35A1470250DD8923A9就是第一组密码+"@DBApp" 的sha1值,由于只有六位,爆破即可,得到123321.

第二个加密是md5,但是爆破失败。先继续往下分析。sub_40100F传入的参数是

char __cdecl sub_4014D0(LPCSTR TarString)
{
  LPCVOID rtfFile; // [esp+50h] [ebp-1Ch]
  DWORD NumberOfBytesWritten; // [esp+58h] [ebp-14h]
  DWORD nNumberOfBytesToWrite; // [esp+5Ch] [ebp-10h]
  HGLOBAL hResData; // [esp+60h] [ebp-Ch]
  HRSRC hResInfo; // [esp+64h] [ebp-8h]
  HANDLE hFile; // [esp+68h] [ebp-4h]

  hFile = 0;
  hResData = 0;
  nNumberOfBytesToWrite = 0;
  NumberOfBytesWritten = 0;
  hResInfo = FindResourceA(0, (LPCSTR)0x65, "AAA");
  if ( !hResInfo )
    return 0;
  nNumberOfBytesToWrite = SizeofResource(0, hResInfo);
  hResData = LoadResource(0, hResInfo);
  if ( !hResData )
    return 0;
  rtfFile = LockResource(hResData);
  sub_401005(TarString, (int)rtfFile, nNumberOfBytesToWrite);
  hFile = CreateFileA("dbapp.rtf", 0x10000000u, 0, 0, 2u, 0x80u, 0);
  if ( hFile == (HANDLE)-1 )
    return 0;
  if ( !WriteFile(hFile, rtfFile, nNumberOfBytesToWrite, &NumberOfBytesWritten, 0) )
    return 0;
  CloseHandle(hFile);
  return 1;
}
/*
以下为sub_401005的关键代码:
/*
  v5 = lstrlenA(TarString);
  for ( i = 0; ; ++i )
  {
    result = i;
    if ( i >= rtfFileLength )
      break;
    *(_BYTE *)(i + rtfFile) ^= TarString[i % v5];
  }
  return result;

使用Resource Hacker打开这个文件,得到:

根据代码,程序会最终输出一个dbapp.rtf的文件,并将其与传入的String异或。

由于rtf文件头已知({\rtf1)因此,可以计算出String的前六位,即第二组6位密码。

exp:

lockedrtf=[0x05,0x7d,0x41,0x15,0x26,0x01]
rtfhead=list("{\\rtf1")
ff=""
for i in range(0,len(rtfhead)):
    ff+=chr(lockedrtf[i]^ord(rtfhead[i]))
print(ff)

得到第一组密码~!3a@0,输入程序,即可在生成的rtf文件中找到flag。


等风来,不如追风去。