2023 香山杯 Reverse

mi1itray.axe published on
6 min, 1002 words

Categories: Reverse

香山杯初赛的3到逆向的WP,不是很难的题,但是有一些新的东西,chaquopy框架,这个框架完成了一套sdk,可以安卓调用python代码也可以python调用java代码。可惜的是python是源码存储,还有研究的空间

URL从哪儿来

题目说明:小A收到一个样本,很轻松就完成了任务:找到样本外联C2。但小A非常好奇的是,他并不能直接在样本中搜到C2,C2是如何被解密的呢?

题目链接:https://github.com/Military-axe/ctf/tree/master/2023/2023%E9%A6%99%E5%B1%B1%E6%9D%AF%E5%88%9D%E8%B5%9B

分析,发现有一个程序会导出一个临时文件,临时文件ou.exe才是真正的逻辑所在

int __cdecl main(int argc, const char **argv, const char **envp)
{
  HMODULE ModuleHandleW; // eax
  HMODULE v4; // eax
  HMODULE v5; // eax
  _BYTE *v7; // [esp+4h] [ebp-28Ch]
  HGLOBAL hResData; // [esp+8h] [ebp-288h]
  HRSRC hResInfo; // [esp+Ch] [ebp-284h]
  _BYTE *lpAddress; // [esp+10h] [ebp-280h]
  FILE *Stream; // [esp+1Ch] [ebp-274h]
  DWORD dwSize; // [esp+20h] [ebp-270h]
  DWORD i; // [esp+28h] [ebp-268h]
  struct _PROCESS_INFORMATION ProcessInformation; // [esp+30h] [ebp-260h] BYREF
  struct _STARTUPINFOA StartupInfo; // [esp+40h] [ebp-250h] BYREF
  CHAR Buffer[260]; // [esp+84h] [ebp-20Ch] BYREF
  CHAR TempFileName[260]; // [esp+188h] [ebp-108h] BYREF

  ModuleHandleW = GetModuleHandleW(0);
  hResInfo = FindResourceW(ModuleHandleW, (LPCWSTR)0x65, L"e_ou");
  v4 = GetModuleHandleW(0);
  hResData = LoadResource(v4, hResInfo);
  v7 = LockResource(hResData);
  v5 = GetModuleHandleW(0);
  dwSize = SizeofResource(v5, hResInfo);
  lpAddress = VirtualAlloc(0, dwSize, 0x1000u, 4u);
  if ( !lpAddress )
    return 1;
  for ( i = 0; i < dwSize; ++i )
  {
    if ( v7[i] && v7[i] != 'x' )
      lpAddress[i] = v7[i] ^ 'x';
    else
      lpAddress[i] = v7[i];
  }
  if ( !GetTempPathA(0x104u, Buffer) )
    return 1;
  if ( !GetTempFileNameA(Buffer, "ou.exe", 0, TempFileName) )
    return 1;
  Stream = fopen(TempFileName, "wb");
  if ( !Stream )
    return 1;
  if ( fwrite(lpAddress, 1u, dwSize, Stream) == dwSize )
  {
    fclose(Stream);
    VirtualFree(lpAddress, 0, 0x8000u);
    memset(&StartupInfo, 0, sizeof(StartupInfo));
    memset(&ProcessInformation, 0, sizeof(ProcessInformation));
    StartupInfo.cb = 68;
    GetStartupInfoA(&StartupInfo);
    StartupInfo.wShowWindow = 0;
    CreateProcessA(TempFileName, 0, 0, 0, 1, 0, 0, 0, &StartupInfo, &ProcessInformation);
    CloseHandle(ProcessInformation.hProcess);
    CloseHandle(ProcessInformation.hThread);
    DeleteFileA(TempFileName);
    return 0;
  }
  else
  {
    fclose(Stream);
    return 1;
  }
}

idapython提取存储在里面的ou.exe

import idc 
s = idc.get_bytes(0x1550000,0x1a800) 
f=open('D:/Desktop/1.exe', 'wb') 
f.write(s) 
f.close()

img

分析ou.exe中代码,main函数中这部分代码,得到block的值是一个base64

imgflag{6469616e-6369-626f-7169-746170617761}

hello_py

题目地址:https://github.com/Military-axe/ctf/tree/master/2023/2023%E9%A6%99%E5%B1%B1%E6%9D%AF%E5%88%9D%E8%B5%9B

这是一个叫chaquopy框架的题目,框架可以在安卓中调用python和python中调用安卓代码两种方式

一开始以为这个框架会把python文件编译成so文件,实际上没有,还是把python文件存在APK文件中

img只是改了一下后缀名,改成app.zip,解开来就是hello.py发现只是一个xxtea加密,改都没改,秒了

exp:

from ctypes import *
from Crypto.Util.number import *

def MX(z, y, total, key, p, e):
    temp1 = (z.value>>5 ^ y.value<<2) + (y.value>>3 ^ z.value<<4)
    temp2 = (total.value ^ y.value) + (key[(p&3) ^ e.value] ^ z.value)
    
    return c_uint32(temp1 ^ temp2)

def decrypt(n, v, key):
    delta = 0x9e3779b9
    rounds = 6 + 52//n 
    
    total = c_uint32(rounds * delta)
    y = c_uint32(v[0])
    e = c_uint32(0)

    while rounds > 0:
        e.value = (total.value >> 2) & 3
        for p in range(n-1, 0, -1):
            z = c_uint32(v[p-1])
            v[p] = c_uint32((v[p] - MX(z,y,total,key,p,e).value)).value
            y.value = v[p]
        z = c_uint32(v[n-1])  
        v[0] = c_uint32(v[0] - MX(z,y,total,key,0,e).value).value
        y.value = v[0]  
        total.value -= delta
        rounds -= 1

    return v 

cipher =[689085350 ,626885696 ,1894439255 ,1204672445 ,1869189675 ,475967424 ,1932042439 ,1280104741 ,2808893494 ]
key = [12345678 ,12398712 ,91283904 ,12378192 ]
n = 9
res = decrypt(n, cipher, key)
flag = b''
for i in res:
    flag+=long_to_bytes(i)[::-1]
print(flag)

flag{c1f8ace6-4b46-4931-b25b-a1010a89c592}

nesting

题目提示:flag{uuid}

题目地址:https://github.com/Military-axe/ctf/tree/master/2023/2023%E9%A6%99%E5%B1%B1%E6%9D%AF%E5%88%9D%E8%B5%9B

这是一个vm题,vm写的很复杂,实际上用污点分析的思路,下几个内存断点,跟踪一下输入的变化,就会发现只是输入和一组值相异或

exp:

xor = [0x54, 0xf6, 0xf2, 7, 0xfb, 4, 5, 0xe, 0x5d, 0x53, 0xc9, 0x4e, 0x46, 0xa, 0x13, 0x1, 0x3, 0x38, 0xa0, 0xbb, 0xc7, 0x44, 0xfa, 0xbc, 0x3, 0x44, 0x2c, 0x9a, 0x6d, 0x98, 0x35, 0x4f, 0x4a, 0x10, 0xc4, 0x17, 0x9, 0x61, 0x6, 0xe1, 0x8d, 0x75]
c = [50, 154, 147, 96, 128, 54, 102, 57, 62, 99, 240, 125, 36, 39, 117, 55, 55, 0, 141, 138, 246, 33, 158, 145, 98, 115, 29, 172, 64, 175, 5, 126, 43, 114, 252, 116, 104, 0, 103, 135, 232, 8]

for i in range(len(xor)):
    c[i] ^= xor[i]

print(bytes(c))
print(xor)