第六届安洵杯 Reverse WriteUp

一. 你见过蓝色的小鲸鱼

  • 找到关键加密函数:

  • CHAR *__cdecl sub_4577E0(HWND hDlg)
    {
      CHAR *result; // eax
      CHAR *v2; // [esp+10h] [ebp-154h]
      void *v3; // [esp+24h] [ebp-140h]
      CHAR *v4; // [esp+114h] [ebp-50h]
      CHAR *lpString; // [esp+120h] [ebp-44h]
      HWND DlgItem; // [esp+12Ch] [ebp-38h]
      HWND hWnd; // [esp+138h] [ebp-2Ch]
      int v8; // [esp+144h] [ebp-20h]
      int WindowTextLengthA; // [esp+150h] [ebp-14h]
    
      __CheckForDebuggerJustMyCode(&unk_52105E);
      hWnd = GetDlgItem(hDlg, 1003);
      DlgItem = GetDlgItem(hDlg, 1004);
      WindowTextLengthA = GetWindowTextLengthA(hWnd);
      v8 = GetWindowTextLengthA(DlgItem);
      lpString = (CHAR *)j__malloc(__CFADD__(WindowTextLengthA, 16) ? -1 : WindowTextLengthA + 16);
      result = (CHAR *)j__malloc(__CFADD__(v8, 16) ? -1 : v8 + 16);
      v4 = result;
      if ( lpString && result )
      {
        GetWindowTextA(hWnd, lpString, WindowTextLengthA + 16);
        GetWindowTextA(DlgItem, v4, v8 + 16);
        v3 = operator new(0x10u);
        if ( v3 )
        {
          sub_451B43(0x10u);
          v2 = (CHAR *)sub_450CE3(v3);
        }
        else
        {
          v2 = 0;
        }
        sub_44FC2B(&unk_51D38C, 0x10u);
        sub_45126F(lpString, WindowTextLengthA, (int)v4, v8);
        sub_450199(v2);
        j__free(lpString);
        j__free(v4);
        result = v2;
        if ( v2 )
          return (CHAR *)sub_44F77B(1);
      }
      return result;
    }
    
    
    int __thiscall sub_4571A0(int this, void *Src, size_t a3, void *a4, size_t a5)
    {
      const void *v5; // eax
      int result; // eax
      size_t v7; // [esp-4h] [ebp-12Ch]
      int v8; // [esp+10h] [ebp-118h]
    
      __CheckForDebuggerJustMyCode(&unk_52102F);
      if ( operator new(0x2Cu) )
      {
        sub_451A4E(0x2Cu);
        v8 = sub_450CBB(Src, a3);
      }
      else
      {
        v8 = 0;
      }
      sub_4521B5(&unk_51C048, &unk_51C000);
      sub_451F08(a4, a5);
      *(_DWORD *)(this + 12) = sub_44FEF6(v8);
      *(_DWORD *)(this + 4) = j_unknown_libname_47(*(_DWORD *)(this + 12));
      v7 = *(_DWORD *)(this + 12);
      v5 = (const void *)sub_4505A4(v8);
      j__memmove(*(void **)(this + 4), v5, v7);
      result = v8;
      if ( v8 )
        return sub_44FF0A(1);
      return result;
    }
    
    
    sub_4521B5(&unk_51C048, &unk_51C000);//两个都是blowfish的表
    
  • 发现为blowfish加密,密钥就是题目用户名(blowfish密钥不定长)

  • 在线网站解密

  • QHRoZWJsdWVmMXNo

  • 也可以脚本解密

  • from Crypto.Cipher import Blowfish
    key=b'UzBtZTBuZV9EMGcz'
    bf=Blowfish.new(key,Blowfish.MODE_ECB)
    enc=b"\x11\xA5\x1F\x04\x95\x50\xE2\x50\x8F\x17\xE1\x6C\xF1\x63\x2B\x47"
    print(bf.decrypt(enc))
    
  • 则有:D0g3{UzBtZTBuZV9EMGczQHRoZWJsdWVmMXNo}

二. 感觉有点点简单

  • 简单题,RC4魔改加base64魔改

  • __int64 sub_1400016F0()
    {
      __int64 v1; // [rsp+20h] [rbp-78h] BYREF
      PVOID NumberOfBytes_4; // [rsp+28h] [rbp-70h]
      PVOID P; // [rsp+30h] [rbp-68h]
      __int64 v4; // [rsp+38h] [rbp-60h]
      __int64 v5; // [rsp+40h] [rbp-58h]
      __int64 v6; // [rsp+48h] [rbp-50h] BYREF
      const char *v7; // [rsp+50h] [rbp-48h]
      const char *v8; // [rsp+58h] [rbp-40h]
      struct _UNICODE_STRING DestinationString; // [rsp+60h] [rbp-38h] BYREF
      char v10[40]; // [rsp+70h] [rbp-28h] BYREF
    
      HIDWORD(v1) = 4096;
      memset(&v6, 0, sizeof(v6));
      RtlInitUnicodeString(&DestinationString, L"\\??\\C:\\Users\\Public\\flag.txt");
      NumberOfBytes_4 = ExAllocatePool(NonPagedPool, 0x1000ui64);
      P = ExAllocatePool(NonPagedPool, 0x1000ui64);
      if ( NumberOfBytes_4 && P )
      {
        v4 = HIDWORD(v1);
        memset(P, 0, HIDWORD(v1));
        v5 = HIDWORD(v1);
        memset(NumberOfBytes_4, 0, HIDWORD(v1));
        qmemcpy(v10, &DestinationString, 0x10ui64);
        LOBYTE(v1) = sub_140001040(v10, v6, NumberOfBytes_4, (char *)&v1 + 4);
        if ( (_BYTE)v1 )
        {
          if ( HIDWORD(v1) <= 0xC00 )
          {
            sub_1400011F0(NumberOfBytes_4, HIDWORD(v1), "the_key_", 8i64, v1);
            sub_140001360((__int64)P, (__int64)NumberOfBytes_4, SHIDWORD(v1));
            LOBYTE(v1) = sub_140001560((__int64)P, 56);
            v8 = "tips: YES, RIGHT FLAG.   you got it!";
            v7 = "tips: NO , WRONG ANSWER. try again !";
            if ( (_BYTE)v1 )
              DbgPrint("tips: %s\n", v8);
            else
              DbgPrint("tips: %s\n", v7);
          }
          else
          {
            DbgPrint("tips: file to long \n");
          }
        }
        else
        {
          DbgPrint("tips: can not read|open file\n");
        }
      }
      else
      {
        DbgPrint("tips: can not malloc\n");
      }
      if ( NumberOfBytes_4 )
      {
        ExFreePoolWithTag(NumberOfBytes_4, 0);
        NumberOfBytes_4 = 0i64;
      }
      if ( P )
      {
        ExFreePoolWithTag(P, 0);
        P = 0i64;
      }
      return 0i64;
    }
    
  • RC4魔改:

  • __int64 __fastcall sub_1400011F0(__int64 a1, unsigned int a2, __int64 a3, unsigned int a4)
    {
      __int64 result; // rax
      unsigned __int8 v5; // [rsp+20h] [rbp-18h]
      unsigned __int8 v6; // [rsp+21h] [rbp-17h]
      unsigned int i; // [rsp+24h] [rbp-14h]
    
      v5 = 0;
      v6 = 0;
      sub_1400015B0(a3, a4);
      for ( i = 0; ; ++i )
      {
        result = a2;
        if ( i >= a2 )
          break;
        v5 = (v5 + 1) % 64;
        v6 = (byte_140003010[v5] + v6) % 64;
        sub_1400018E0(&byte_140003010[v5], &byte_140003010[v6]);
        *(_BYTE *)(a1 + i) ^= (v6 ^ v5) & byte_140003010[(unsigned __int8)(((v6 ^ v5)
                                                                          + byte_140003010[v6]
                                                                          + byte_140003010[v5])
                                                                         % 64)];
      }
      return result;
    }
    
  • base64魔改:

  • __int64 __fastcall sub_140001360(__int64 a1, __int64 a2, int a3)
    {
      int v4; // [rsp+0h] [rbp-88h]
      int v5; // [rsp+4h] [rbp-84h]
      char v6[80]; // [rsp+10h] [rbp-78h] BYREF
    
      strcpy(v6, "4KBbSzwWClkZ2gsr1qA+Qu0FtxOm6/iVcJHPY9GNp7EaRoDf8UvIjnL5MydTX3eh");
      v4 = 0;
      v5 = 0;
      while ( v4 < a3 )
      {
        *(_BYTE *)(a1 + v5) = v6[*(_BYTE *)(a2 + v4) & 0x3F];
        *(_BYTE *)(a1 + v5 + 1) = v6[(4 * (*(_BYTE *)(a2 + v4 + 1) & 0xF)) | ((*(_BYTE *)(a2 + v4) & 0xC0) >> 6)];
        *(_BYTE *)(a1 + v5 + 2) = v6[(16 * (*(_BYTE *)(a2 + v4 + 2) & 3)) | ((*(_BYTE *)(a2 + v4 + 1) & 0xF0) >> 4)];
        *(_BYTE *)(a1 + v5 + 3) = v6[(*(_BYTE *)(a2 + v4 + 2) & 0xFC) >> 2];
        v4 += 3;
        v5 += 4;
      }
      if ( a3 % 3 == 1 )
      {
        *(_BYTE *)(a1 + v5 - 2) = 61;
        *(_BYTE *)(a1 + v5 - 1) = 61;
      }
      else if ( a3 % 3 == 2 )
      {
        *(_BYTE *)(a1 + v5 - 1) = 61;
      }
      return 0i64;
    }
    
  • 检验:

  • bool __fastcall sub_140001560(__int64 a1, int a2)
    {
      return a2 == 56 && !(unsigned int)sub_1400019F0(a1, "6zviISn2McHsa4b108v29tbKMtQQXQHA+2+sTYLlg9v2Q2Pq8SP24Uw=", 56i64);
    }
    
  • 编写脚本:

  • def KSA(key):
        key_length = len(key)
        S = list(range(64))
        j = 0
        for i in range(64):
            j = (j + S[i] + key[i % key_length]) % 64
            S[i], S[j] = S[j], S[i]
        return S
    
    
    def PRGA(S):
        i = 0
        j = 0
        while True:
            i = (i + 1) % 64
            j = (j + S[i]) % 64
            S[i], S[j] = S[j], S[i]
            K = (i^j) & S[(((i^j)+S[i] + S[j]) % 64)]
            yield K
    
    
    def RC4(key):
        S = KSA(key)
        keystream = PRGA(S)
        return keystream
    
    
    if __name__ == '__main__':
        key = 'the_key_'
        c = '6zviISn2McHsa4b108v29tbKMtQQXQHA+2+sTYLlg9v2Q2Pq8SP24Uw4'
        table = '4KBbSzwWClkZ2gsr1qA+Qu0FtxOm6/iVcJHPY9GNp7EaRoplaintextf8UvIjnL5MyplaintextTX3eh'
    
        # c = c.replace('=', table[0])
        plaintext = []
        for i in range(0, len(c), 4):
            x = [table.inplaintextex(j) for j in c[i: i + 4]]
            plaintext.append(x[0] | ((x[1] & 3) << 6))
            plaintext.append((x[1] >> 2) | ((x[2] & 0xf) << 4))
            plaintext.append((x[2] >> 4) | (x[3] << 2))
        print(plaintext)
        key = key.encode()
        keystream = RC4(key)
        ciphertext = []
        for b in plaintext:
            ciphertext.append(chr(b ^ next(keystream)))
        print("".join(ciphertext))
    
  • D0g3{608292C4-15400BA4-B3299A5C-704C292D}

  • 注意:可以把原密文最后的等号直接替换成table[0]

三. 牢大想你了

  • 直接反编译**"\GalgamePro_BackUpThisFolder_ButDontShipItWithYourGame\Managed\Assembly-CSharp.dll"**

  • 	public void OnValueChanged(string ABBAAAABBBBAAABABBBABAAABAABAABBABBBBABAABAABAB)
    	{
    		uint[] str = new uint[]
    		{
    			286331153U,
    			286331153U,
    			286331153U,
    			286331153U
    		};
    		byte[] strBytes = Encoding.UTF8.GetBytes(ABBAAAABBBBAAABABBBABAAABAABAABBABBBBABAABAABAB);
    		int paddingCount = 8 - strBytes.Length % 8;
    		byte[] paddedArray = new byte[strBytes.Length + paddingCount];
    		Array.Copy(strBytes, paddedArray, strBytes.Length);
    		uint[] uintArray = new uint[paddedArray.Length / 4];
    		Buffer.BlockCopy(paddedArray, 0, uintArray, 0, paddedArray.Length);
    		uint[] encryptedData = new uint[0];
    		AAABAAABABABAAABBABBABAAAABBAABBAABABBBBBABAAAB str2 = new AAABAAABABABAAABBABBABAAAABBAABBAABABBBBBABAAAB(str);
    		for (int i = 0; i < uintArray.Length; i += 2)
    		{
    			encryptedData = encryptedData.Concat(str2.BABBBBBBAAAAAABABBBAAAABBABBBAABABAAABABBAAABBA(uintArray[i], uintArray[i + 1])).ToArray<uint>();
    		}
    		uint[] array = new uint[]
    		{
    			3363017039U,
    			1247970816U,
    			549943836U,
    			445086378U,
    			3606751618U,
    			1624361316U,
    			3112717362U,
    			705210466U,
    			3343515702U,
    			2402214294U,
    			4010321577U,
    			2743404694U
    		};
    		MonoBehaviour.print(array);
    		if (array.SequenceEqual(encryptedData))
    		{
    			this.BBBAAAAABABABABBABAAAAABBABBAABBABABABABBBABAAB = 5;
    			this.ABAABAAABABABABABBBBBAAABBAABBBBBAABAAAABBABABB("port");
    			this.BAABAABBABABABABBBABBBBABBBBBBBABABBAABBABABABB("牢大");
    			this.AAAABBABAAAABBAABAABAABAABBBAAABBBABBBBBAABABBA("哈哈,我没有变成耐摔王");
    			return;
    		}
    		this.BBBAAAAABABABABBABAAAAABBABBAABBABABABABBBABAAB = 5;
    		this.ABAABAAABABABABABBBBBAAABBAABBBBBAABAAAABBABABB("耐摔王");
    		this.BAABAABBABABABABBBABBBBABBBBBBBABABBAABBABABABB("狂暴牢大");
    		this.AAAABBABAAAABBAABAABAABAABBBAAABBBABBBBBAABABBA("获得成就“耐摔王”");
    	}
    
  • 找到关键加密函数:

  • 	// Token: 0x060000AA RID: 170 RVA: 0x000058FC File Offset: 0x00003AFC
    	public uint[] BABBBBBBAAAAAABABBBAAAABBABBBAABABAAABABBAAABBA(uint ABBAABAAAAAABAAAABBBBBBABAABAAAABBBABBBAABBABBA, uint BAABBAAAAABABBAABBABBAABABABABABABAAABABBBABABA)
    	{
    		uint v0 = ABBAABAAAAAABAAAABBBBBBABAABAAAABBBABBBAABBABBA;
    		uint v = BAABBAAAAABABBAABBABBAABABABABABABAAABABBBABABA;
    		uint sum = 0U;
    		uint delta = 2654435769U;
    		uint[] str2 = this.BBABABBBABBABABAAABBBAABBAAAAAAABBBBBAABBAAAAAA;
    		for (int i = 0; i < 32; i++)
    		{
    			sum += delta;
    			v0 += ((v << 4) + str2[0] ^ v + sum ^ (v >> 5) + str2[1]);
    			v += ((v0 << 4) + str2[2] ^ v0 + sum ^ (v0 >> 5) + str2[3]);
    		}
    		return new uint[]
    		{
    			v0,
    			v
    		};
    	}
    
  • 这些混淆不去也罢,也能看懂

  • tea,直接套脚本解密:

  • from ctypes import *
    
    def decrypt(v, k):
        v0 = c_uint32(v[0])
        v1 = c_uint32(v[1])
        delta = 2654435769
        sum1 = c_uint32(delta*32)
        for i in range(32):
            v1.value -= ((v0.value << 4) + k[2]) ^ (v0.value + sum1.value) ^ ((v0.value >> 5) + k[3])
            v0.value -= ((v1.value << 4) + k[0]) ^ (v1.value + sum1.value) ^ ((v1.value >> 5) + k[1])
            sum1.value -= delta
        return v0.value.to_bytes(4,'little')+v1.value.to_bytes(4,'little')
    
    
    if __name__ == '__main__':
        a=[3363017039,1247970816]
        a1=[549943836,445086378]
        a2=[3606751618,1624361316]
        a3=[3112717362,705210466]
        a4=[3343515702,2402214294]
        a5=[4010321577,2743404694]
        k=[286331153, 286331153, 286331153, 286331153]
        res= decrypt(a, k)+decrypt(a1,k)+decrypt(a2,k)+decrypt(a3,k)+decrypt(a4,k)+decrypt(a5,k)
        print("解密后数据:", res)
    
    • D0g3{it_is_been_a_long_day_without_you_my_friend}

四. mobilego

  • MainActivity如下:

  • package com.example.mobilego;
    
    import android.os.Bundle;
    import android.view.View;
    import android.widget.Button;
    import android.widget.EditText;
    import android.widget.Toast;
    import androidx.appcompat.app.AppCompatActivity;
    import game.Game;
    
    /* loaded from: classes3.dex */
    public class MainActivity extends AppCompatActivity {
        private Button button;
        private EditText editText;
    
        /* JADX INFO: Access modifiers changed from: protected */
        @Override // androidx.fragment.app.FragmentActivity, androidx.activity.ComponentActivity, androidx.core.app.ComponentActivity, android.app.Activity
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            this.editText = (EditText) findViewById(R.id.editText);
            Button button = (Button) findViewById(R.id.button);
            this.button = button;
            button.setOnClickListener(new View.OnClickListener() { // from class: com.example.mobilego.MainActivity$$ExternalSyntheticLambda0
                @Override // android.view.View.OnClickListener
                public final void onClick(View view) {
                    MainActivity.this.m44lambda$onCreate$0$comexamplemobilegoMainActivity(view);
                }
            });
        }
    
        /* JADX INFO: Access modifiers changed from: package-private */
        /* renamed from: lambda$onCreate$0$com-example-mobilego-MainActivity  reason: not valid java name */
        public /* synthetic */ void m44lambda$onCreate$0$comexamplemobilegoMainActivity(View v) {
            if (Game.checkflag(this.editText.getText().toString()).equals(getResources().getString(R.string.cmp))) {
                Toast.makeText(this, "yes your flag is right", 0).show();
            } else {
                Toast.makeText(this, "No No No", 0).show();
            }
        }
    }
    
  • 注意checkflag函数为native函数

  • frida简单调试一下,发现是一个替换

  • cmp='49021}5f919038b440139g74b7Dc88330e5d{6'
    tmp='vIlDoLjtEpkCmyzfqbshucxwiAagKFBdGHJner'
    table='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKL'
    flag=''
    for i in table:
        for j in tmp:
            if ord(i)==ord(j):
                flag+=cmp[tmp.index(j)]
            else:
                continue
    print(flag)
    
  • D0g3{4c3b5903d11461f94478b7302980e958}

五. 你好PE

  • int __cdecl main_0(int argc, const char **argv, const char **envp)
    {
      int v4; // [esp+4Ch] [ebp-10h] BYREF
      int v5; // [esp+50h] [ebp-Ch]
      LPVOID lpAddress; // [esp+54h] [ebp-8h]
    
      __CheckForDebuggerJustMyCode(&unk_51E018);
      v5 = 0;
      v4 = 0;
      lpAddress = (LPVOID)sub_450DF0();             // 获取资源文件
      if ( lpAddress )
      {
        v5 = sub_44E753(0, lpAddress, 1, &v4);      // 资源文件进行加密
        VirtualFree(lpAddress, 0, 0x8000u);
        return v4;
      }
      else
      {
        sub_44EA73("find res failed\n");
        return 0;
      }
    }
    
  • 实现对资源文件的加密操作

  • 跟进找资源文件

  • int __cdecl sub_455DB0(int a1, int a2, int a3, int a4)
    {
      __CheckForDebuggerJustMyCode(&unk_51E02A);
      switch ( a1 )
      {
        case 0:
          return sub_4513F9(a2, a3 != 0, a4);
        case 1:
          sub_44F89C(a2);
          break;
        case 2:
          return sub_44F2A7(a2, a3);
      }
      return 0;
    }
    
  • _DWORD *__cdecl sub_455750(int a1, int a2, _DWORD *a3)
    {
      void (__stdcall *v4)(_DWORD *); // [esp+4Ch] [ebp-10h]
      _DWORD *v5; // [esp+50h] [ebp-Ch]
      int v6; // [esp+58h] [ebp-4h]
    
      __CheckForDebuggerJustMyCode(&unk_51E02A);
      v6 = sub_450FAD();
      if ( v6 )
      {
        v5 = (_DWORD *)(*(int (__stdcall **)(int, int))(v6 + 24))(64, 28);
        if ( v5 )
        {
          v5[3] = v6;
          v5[4] = a2;
          v5[5] = 0;
          v5[6] = 0;
          if ( sub_44FCC5(v5, a1, a2) )
          {
            if ( a3 )
              *a3 = 0;
            return v5;
          }
          else
          {
            if ( a3 )
              *a3 = v5[6];
            v4 = *(void (__stdcall **)(_DWORD *))(v6 + 28);
            v4(v5);
            v4((_DWORD *)v6);
            return 0;
          }
        }
        else
        {
          if ( a3 )
            *a3 = 255;
          return 0;
        }
      }
      else
      {
        if ( a3 )
          *a3 = 255;
        return 0;
      }
    }
    
  • 注意到此处的a1就是资源文件起始地址

  • 跟进

  • int __cdecl sub_455870(_DWORD *a1, int a2, int a3)
    {
      __CheckForDebuggerJustMyCode(&unk_51E02A);
      if ( !a1 || !a1[3] || !a2 )
        return 0;
      a1[6] = 0;
      if ( !sub_44FED7(a1, a2) )
        return 0;
      if ( !sub_44EB77(a1, a2) )
        return 0;
      if ( !sub_44F478(a1) )
        goto LABEL_17;
      if ( !sub_451057(a1) )
        goto LABEL_17;
      a1[2] = sub_450D69(0, *a1, a1[1]);
      if ( !sub_45016B(a1) )
        goto LABEL_17;
      if ( !sub_4509DB(a1) )
        return 0;
      if ( !a3 || sub_44ED5C(a1, 1) )
        return 1;
    LABEL_17:
      sub_44EFD2(a1);
      return 0;
    }
    
  • 调试发现直到sub_44ED5C函数才出现输入flag

  • 跟进

  • int __cdecl sub_3A4B40(_DWORD *a1, int a2)
    {
      void (__cdecl *v3)(_DWORD, int, _DWORD); // [esp+4Ch] [ebp-8h]
      int v4; // [esp+50h] [ebp-4h]
    
      if ( !a1 || !*a1 )
        return 0;
      v4 = *(_DWORD *)(*a1 + 60) + *a1;
      if ( !*(_DWORD *)(v4 + 40) )
        return 0;
      v3 = (void (__cdecl *)(_DWORD, int, _DWORD))(*(_DWORD *)(v4 + 40) + *a1);
      if ( v3 )
      {
        v3(*a1, a2, 0);
        return 1;
      }
      else
      {
        a1[6] = 6;
        return 0;
      }
    }
    
  • 实际上是v3对资源文件进行了改动

  • 跟进找到加密函数:

  • int sub_1005F820()
    {
      _DWORD *v1; // [esp+D0h] [ebp-8h]
    
      sub_1005B16F(&unk_1014000F);
      kernel32_VirtualAlloc(0, 65548, 12288, 4);
      v1 = (_DWORD *)sub_1005A260();
      if ( !v1 )
        return -1;
      v1[1] = 0x10000;
      *v1 = 0;
      v1[2] = v1 + 3;
      sub_10059572(v1[2], 0, v1[1]);
      ((void (__cdecl *)(const char *))unk_10058BC7)("[out]: PLZ Input FLag \n");
      ((void (__cdecl *)(const char *))unk_10058BC7)("[in ]: ");
      ((void (__cdecl *)(void *, _DWORD))unk_100581A4)(&unk_10114B68, v1[2]);
      *v1 = sub_1005B5BB(v1[2]);
      if ( *v1 == 41 )
      {
        *v1 = 48;
        ((void (__cdecl *)(_DWORD *))unk_1005A242)(v1);
        if ( ((int (__cdecl *)(_DWORD, void *, int))unk_10058AA0)(v1[2], &unk_1013C008, 48) )
          ((void (__cdecl *)(const char *))unk_10058BC7)("[out]: WRONG FLAG\n");
        else
          ((void (__cdecl *)(const char *))unk_10058BC7)("[out]: RIGHT FLAG\n");
        kernel32_VirtualFree(v1, 0, 49152);
        sub_1005A260();
        return 0;
      }
      else
      {
        ((void (__cdecl *)(const char *))unk_10058BC7)("[out]: len error\n");
        kernel32_VirtualFree(v1, 0, 49152);
        sub_1005A260();
        return -1;
      }
    }
    
  • 把数据p完找到加密函数:

  • _DWORD *__cdecl sub_1005F6F0(_DWORD *a1)
    {
      _DWORD *result; // eax
      int v2; // ecx
      int j; // [esp+D0h] [ebp-30h]
      unsigned int i; // [esp+DCh] [ebp-24h]
      __int64 v5; // [esp+E8h] [ebp-18h]
      int *v6; // [esp+F8h] [ebp-8h]
    
      sub_1005B16F(&unk_1014000F);
      for ( i = 0; ; ++i )
      {
        result = a1;
        if ( i >= *a1 >> 3 )
          break;
        v6 = (int *)(a1[2] + 8 * i);
        v2 = *v6;
        v5 = *(_QWORD *)v6;
        for ( j = 0; j < 64; ++j )
        {
          LOBYTE(v2) = 1;
          if ( v5 < 0 )
            v5 = qword_1013C000 ^ sub_10059F9F(v2, HIDWORD(v5));
          else
            v5 = sub_10059F9F(v2, HIDWORD(v5));
        }
        *(_QWORD *)v6 = v5;
      }
      return result;
    }
    
  • 注意如下汇编代码:

  • debug034:1005F738 mov     eax, [ebp+arg_0]
    debug034:1005F73B mov     ecx, [eax+8]
    debug034:1005F73E mov     edx, [ebp+var_24]
    debug034:1005F741 lea     eax, [ecx+edx*8]
    debug034:1005F744 mov     [ebp+var_8], eax
    debug034:1005F747 mov     eax, [ebp+var_8]
    debug034:1005F74A mov     ecx, [eax]
    debug034:1005F74C mov     edx, [eax+4]
    debug034:1005F74F mov     dword ptr [ebp+var_18], ecx
    debug034:1005F752 mov     dword ptr [ebp+var_18+4], edx
    
  • 与伪代码有点区别

 LODWORD(v5) = *(_DWORD *)v6;    
 HIDWORD(v5) = v2;
  • 根据这个再去编写脚本(真的是坑www

  • #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    #include <Windows.h>
    #include <windef.h>
    
    int main()
    {
        __int64 key = 0x54aa4a9;
        BYTE c[] = {
                0x4D,0xB8,0x76,0x29,0xF5,0xA9,0x9E,0x59,
                0x55,0x56,0xB1,0xC4,0x2F,0x21,0x2C,0x30,
                0xB3,0x79,0x78,0x17,0xA8,0xED,0xF7,0xDB,
                0xE1,0x53,0xF0,0xDB,0xE9,0x03,0x51,0x5E,
                0x09,0xC1,0x00,0xDF,0xF0,0x96,0xFC,0xC1,
                0xB5,0xE6,0x62,0x95,0x01,0x00,0x00,0x00,
        };
        __int64 v5;
        int j, i;
        for (i = 0; i < 6; i++)
        {
            v5 = *((__int64*)&c[i * 8]);
            for (j = 0; j < 64; j++)
            {
                if (v5 & 1)
                {
                    v5 = ((unsigned __int64)v5 ^ key) >> 1;
                    v5 |= 0x8000000000000000;
    
                }
                else
                {
                    v5 = (unsigned __int64)v5 >> 1;
                }
            }
            *((__int64*)&c[i * 8]) = v5;
        }
        for (i = 0; i < 48; i++)
            printf("%c", c[i]);
        return 0;
    }
    
  • 还要补全符号位

  • D0g3{60E1E72A-576A8BF0-7701CBB9-B02415EC}

总结

  • 注意程序实现及脚本编写的细节!!!