Loading

安洵杯re部分wp

安洵杯re复现

难度还可以,学了很多新东西。

mobilego

ida打开so文件,借助go parser分析go语言逻辑。但是不清楚为什么找不到随机数种子

贴一篇静态分析go语言的好文[原创]GoJni 协议加解密分析-Android安全-看雪-安全社区|安全招聘|kanxue.com

这里选择动调,因为根据密文49021}5f919038b440139g74b7Dc88330e5d{6推测加密是对原文的简单乱序。使用jeb动调跟踪下原文的变化。

原文为FLAG{abcdefghijklmnopqrstuvwxyz012345},变换后为q3gyj}eozkfxhtuallncpasrdvfb50wg124i{m

用雷电模拟器调试时遇到jeb里v0 - v2寄存器存储的值均为void的问题,排查发现不是jeb的问题,更换为真机调试运行正常。也许是因为模拟器没有配置好。

脚本

a = "q3gyj}eozkfxhtualLncpAsrdvFb50wG124i{m"
b = "49021}5f919038b440139g74b7Dc88330e5d{6"
c = r"FLAG{abcdefghijklmnopqrstuvwxyz012345}"
flag = ''
 
for i in c:
    for j in range(len(a)):
        if i == a[j]:
            flag += b[j]
 
print(flag)

你见过蓝色的小鲸鱼

无法识别关键函数,借助IDA动调,给MessageBoxA函数下断点后回溯栈帧。

初步找到显示最终正误结果的函数

检查交叉引用追踪到sub_4577E0

CHAR *__cdecl sub_4577E0(HWND hDlg)
{
  CHAR *result; // eax
  void *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 WindowTextLengthA; // [esp+144h] [ebp-20h]
  int Size; // [esp+150h] [ebp-14h]

  __CheckForDebuggerJustMyCode(&unk_52105E);
  hWnd = GetDlgItem(hDlg, 1003);
  DlgItem = GetDlgItem(hDlg, 1004);
  Size = GetWindowTextLengthA(hWnd);
  WindowTextLengthA = GetWindowTextLengthA(DlgItem);
  lpString = (CHAR *)j__malloc(__CFADD__(Size, 16) ? -1 : Size + 16);
  result = (CHAR *)j__malloc(__CFADD__(WindowTextLengthA, 16) ? -1 : WindowTextLengthA + 16);
  v4 = result;
  if ( lpString && result )
  {
    GetWindowTextA(hWnd, lpString, Size + 16);
    GetWindowTextA(DlgItem, v4, WindowTextLengthA + 16);
    v3 = operator new(0x10u);
    if ( v3 )
    {
      sub_451B43(0x10u);
      v2 = (void *)sub_450CE3(v3);
    }
    else
    {
      v2 = 0;
    }
    sub_44FC2B(&unk_51D38C, 0x10u);
    sub_45126F(lpString, Size, (int)v4, WindowTextLengthA);		//加密函数
    sub_450199(v2);		//show result
    j__free(lpString);
    j__free(v4);
    result = (CHAR *)v2;
    if ( v2 )
      return (CHAR *)sub_44F77B(1);
  }
  return result;
}

v4为密码框内容,lpstring为用户名框内容,可以确定sub_45126F为加密函数。进45126F可看到如下函数

int __thiscall sub_4571A0(int this, void *Src, size_t Size, 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, Size);
  }
  else
  {
    v8 = 0;
  }
  sub_4521B5(&unk_51C048, &unk_51C000);
  sub_451F08(a4, a5);
  *(_DWORD *)(this + 12) = sub_44FEF6(v8);
  *(_DWORD *)(this + 4) = sub_450315(*(_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;
}

4521B5引用的地址存放的是blowfish的sbox和pbox。另外FindCrypt也识别出了blowfish的特征,猜测是拿用户名做密钥对密码进行加密。

另外在sub_45126F前,sub_44FC2B访问了unk_51D38C地址,推测存储的是密文。写脚本解密得用户名。

from Crypto.Cipher import Blowfish  
  
# Blowfish  
key = bytes([0x55, 0x7A, 0x42, 0x74, 0x5A, 0x54, 0x42, 0x75, 0x5A, 0x56, 0x39, 0x45, 0x4D, 0x47, 0x63, 0x7A])  
enc_b = bytes([0x11, 0xA5, 0x1F, 0x04, 0x95, 0x50, 0xE2, 0x50, 0x8F, 0x17, 0xE1, 0x6C, 0xF1, 0x63, 0x2B, 0x47])  
  
cipher = Blowfish.new(key, Blowfish.MODE_ECB)  
dec = cipher.decrypt(enc_b)  
for i in dec:  
    print(chr(i), end='')  
print()

得到16位密码QHRoZWJsdWVmMXNo输入源程序测试成功

感觉有点点简单

用IDA64直接加载,主函数逻辑不复杂。

__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);//核心加密1,RC4
        sub_140001360((char *)P, (__int64)NumberOfBytes_4, SHIDWORD(v1));//核心加密2,base64
        LOBYTE(v1) = sub_140001560(P, 56i64);
        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;
}

sub_1400011F0为RC4加密,sub_140001360为base64加密

sub_1400011F0://RC4加密函数,解密直接异或回去即可

__int64 __fastcall sub_1400011F0(char *a1, unsigned int a2, char *a3, 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]);//交换
    a1[i] ^= (v6 ^ v5) & byte_140003010[(unsigned __int8)(((v6 ^ v5) + byte_140003010[v6] + byte_140003010[v5]) % 64)];
  }
  return result;
}

sub_1400015B0://

__int64 __fastcall sub_1400015B0(char *a1, int a2)
{
  __int64 result; // rax
  int k; // [rsp+20h] [rbp-68h]
  unsigned int i; // [rsp+24h] [rbp-64h]
  int j; // [rsp+28h] [rbp-60h]
  int v6; // [rsp+2Ch] [rbp-5Ch]
  char v7[64]; // [rsp+30h] [rbp-58h] BYREF

  for ( i = 0; i < 0x40; ++i )
    byte_140003010[i] = i;
  result = 0i64;
  memset(v7, 0, sizeof(v7));
  for ( j = 0; j < 64; ++j )
  {
    v7[j] = a1[j % a2];
    result = (unsigned int)(j + 1);
  }
  v6 = 0;
  for ( k = 0; k < 64; ++k )
  {
    v6 = ((unsigned __int8)v7[k] + byte_140003010[k] + v6) % 64;
    sub_1400018E0(&byte_140003010[k], &byte_140003010[v6]);//交换
    result = (unsigned int)(k + 1);
  }
  return result;
}

sub_140001360:

__int64 __fastcall sub_140001360(char *a1, char *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 )
  {
    a1[v5] = v6[a2[v4] & 0x3F];
    a1[v5 + 1] = v6[(4 * (a2[v4 + 1] & 0xF)) | ((a2[v4] & 0xC0) >> 6)];
    a1[v5 + 2] = v6[(16 * (a2[v4 + 2] & 3)) | ((a2[v4 + 1] & 0xF0) >> 4)];
    a1[v5 + 3] = v6[(a2[v4 + 2] & 0xFC) >> 2];
    v4 += 3;
    v5 += 4;
  }
  if ( a3 % 3 == 1 )
  {
    a1[v5 - 2] = '=';
    a1[v5 - 1] = '=';
  }
  else if ( a3 % 3 == 2 )
  {
    a1[v5 - 1] = 61;
  }
  return 0i64;
}

解密脚本:

def locateat(a):
    pz="4KBbSzwWClkZ2gsr1qA+Qu0FtxOm6/iVcJHPY9GNp7EaRoDf8UvIjnL5MydTX3eh"
    i=0
    while(i<64):
        if(pz[i]==a):
            return i
        i=i+1  
def decrypt(a1):
    key="the_key_"
    byte_140003010=[]
    for i in range(0x40):
        byte_140003010.append(i)
    v7=[]
    for j in range(64):
        v7.append(ord(key[j%8]))
    v6 = 0
    
    for k in range(64):
        v6 = (int(v7[k]) + int(byte_140003010[k]) + int(v6)) % 64
        byte_140003010[k], byte_140003010[v6]= byte_140003010[v6],byte_140003010[k]
    v5=0
    v6=0
    for i in range(41):
        v5 = (v5 + 1) % 64
        v6 = (int(byte_140003010[v5]) + v6) % 64
        byte_140003010[v5], byte_140003010[v6]=byte_140003010[v6], byte_140003010[v5]
        a1[i] ^= (v6 ^ v5) & byte_140003010[(((v6 ^ v5) + int(byte_140003010[v6]) + int(byte_140003010[v5])) % 64)]
    return a1
def debase64(a2):
    a1=[]
    i=0
    j=0
    while(i<40):
        try:
            a1.append(locateat(a2[j])|((locateat(a2[j+1])&(0x3))<<6))
            a1.append((locateat(a2[j+1])& 0x3C)>>2|(locateat(a2[j+2])&0xF)<<4)
            a1.append((locateat(a2[j+2])&0x30)>>4|locateat(a2[j+3])<<2)
        except:
            print(str(i)+" "+str(j))
        i=i+3
        j=j+4
    return a1

if __name__=='__main__':
    b="6zviISn2McHsa4b108v29tbKMtQQXQHA+2+sTYLlg9v2Q2Pq8SP24Uw"
    a=decrypt(debase64(b))
    i=0
    c=[]
    for i in a:
        print(chr(i)+"")
    #flag:D0g3{608292C4-15400BA4-B3299A5C-704C292D}

牢大想你了

游戏逆向,打开Assembly_CSharp.dll,定位到GameManager.OnValueChanged

	// Token: 0x06000005 RID: 5 RVA: 0x00002240 File Offset: 0x00000440
	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("获得成就“耐摔王”");
	}

其中str2所在类有个tea加密方法

// Token: 0x02000004 RID: 4
internal class AAABAAABABABAAABBABBABAAAABBAABBAABABBBBBABAAAB
{
	// Token: 0x060000A2 RID: 162 RVA: 0x0000555C File Offset: 0x0000375C
	public uint[] BBBABBABABAAABAAAAABAAABBABBABAAABBABBAABBBAABA(uint ABBAABAAAAAABAAAABBBBBBABAABAAAABBBABBBAABBABBA, uint BAABBAAAAABABBAABBABBAABABABABABABAAABABBBABABA)
	{
		uint v0 = ABBAABAAAAAABAAAABBBBBBABAABAAAABBBABBBAABBABBA;
		uint v = BAABBAAAAABABBAABBABBAABABABABABABAAABABBBABABA;
		uint sum = 1U;
		uint delta = 4294967165U;
		uint[] str2 = this.BBABABBBABBABABAAABBBAABBAAAAAAABBBBBAABBAAAAAA;
		for (int i = 0; i < 91; i += 0)
		{
			sum += delta;
			v0 += ((v << 1) + str2[0] ^ v + sum ^ (v >> 4) + str2[1]);
			v += ((v0 << 5) + str2[5] ^ v0 + sum ^ (v0 >> 6) + str2[3]);
		}
		uint[] array = new uint[2];
		array[0] = v0;
		array[0] = v;
		return array;
	}

搜个脚本解密即可。

你好PE

先静态看,main函数里的sub_760DF0实现了加载资源

hResInfo存储了资源地址的地址,dwSize存储了资源大小,v1是新分配了一部分空间存储资源,函数返回v1的地址。后面的逻辑静态不太好看,动调跟踪下。(具体参考2023安洵杯第六届网络安全挑战赛 Re 部分WriteUp - L3iSu7e's Blog

lpaddress存储的就是复制后资源的地址,跟进sub_75E753。

a1是0,只执行case0。跟踪到下图所示位置,调试发现sub_75ED5C函数是关键,进入。

发现一个可疑位置,根据v3的地址可以访问。实际上这里是进入了pe文件。

进入后很多函数都没有识别,要手动将数据转成代码让ida重新分析。转换后发现sub_10059C11为真正的main函数。

加密函数和官方wp里给的不太一样,加密函数的分析和脚本参考官方wp了。不知道是不是因为没有去掉checkfordebuggerjustmycode的原因。

参考

  1. 2023“安洵杯”网络安全挑战赛wp-CSDN博客
  2. 2023安洵杯第六届网络安全挑战赛 Re 部分WriteUp - L3iSu7e's Blog
  3. 安洵杯2023 RE 你好PE WP_【2023“安洵杯”校园赛】你好,pe-CSDN博客
  4. 安洵DCE平台 (i-soon.net)
posted @ 2024-01-19 14:48  yuhury  阅读(10)  评论(0编辑  收藏  举报