技术 · 2024年7月22日

WKCTF 个人部分

第二

re(527)

so_easy(252)

主要函数

__int64 __fastcall Java_com_so_easy_MainActivity_soEasy(__int64 a1, __int64 a2, __int64 a3)
{
  unsigned int v5; // r13d
  const char *v6; // rax
  const char *v7; // r12
  size_t v8; // rax
  size_t v9; // r8
  __int64 v10; // rsi
  int v11; // edx
  __int64 v12; // rdi
  __int64 v13; // rsi
  __int64 v14; // rdi
  __int64 v15; // rcx
  size_t v16; // rax
  size_t v17; // rcx
  unsigned __int8 v18; // di
  __int128 v20[6]; // [rsp+0h] [rbp-98h] BYREF
  int v21; // [rsp+60h] [rbp-38h]
  unsigned __int64 v22; // [rsp+68h] [rbp-30h]

  v22 = __readfsqword(0x28u);
  v5 = 0;
  v6 = (const char *)(*(__int64 (__fastcall **)(__int64, __int64, _QWORD))(*(_QWORD *)a1 + 1352LL))(a1, a3, 0LL);
  v7 = v6;
  memset(v20, 0, sizeof(v20));
  v21 = 0;
  if ( *v6 )
  {
    v8 = strlen(v6);
    v9 = 0LL;
    do
    {
      v10 = *(_QWORD *)&v7[v9];
      v11 = 255;
      do
      {
        v12 = (2 * v10) ^ 0x71234EA7D92996F5LL; // 对输入字符串的每个8字节块进行多次位运算:
        if ( v10 >= 0 )
          v12 = 2 * v10;
        v13 = (2 * v12) ^ 0x71234EA7D92996F5LL;
        if ( v12 >= 0 )
          v13 = 2 * v12;
        v14 = (2 * v13) ^ 0x71234EA7D92996F5LL;
        if ( v13 >= 0 )
          v14 = 2 * v13;
        v15 = (2 * v14) ^ 0x71234EA7D92996F5LL;
        if ( v14 >= 0 )
          v15 = 2 * v14;
        v10 = (2 * v15) ^ 0x71234EA7D92996F5LL;
        if ( v15 >= 0 )
          v10 = 2 * v15;
        v11 -= 5;
      }
      while ( v11 );
      *(_QWORD *)((char *)v20 + v9) = v10;
      v9 += 8LL;
    }
    while ( v8 > v9 );
  }
  if ( *v7 )
  {
    v16 = strlen(v7);
    v17 = 0LL;
    LOBYTE(v5) = 0;
    do
    {
      v18 = v5 + (*(_WORD *)((char *)v20 + v17) == *(_WORD *)((char *)&unk_560 + v17));
      v17 += 2LL;
      v5 = v18;
    }
    while ( v16 > v17 );
  }
  (*(void (__fastcall **)(__int64, __int64, const char *))(*(_QWORD *)a1 + 1360LL))(a1, a3, v7);
  return v5;
}

多次位分析最后和unk_560比较

unk_560[] =
{
  0xAE, 0x81, 0xBA, 0xC1, 0xF0, 0x95, 0x0A, 0x54, 0x14, 0x03, 
  0x4A, 0xE2, 0x52, 0x4E, 0x84, 0xF8, 0xC9, 0x3E, 0x14, 0x98, 
  0x8F, 0x98, 0xFD, 0x09, 0x5E, 0xAD, 0x05, 0xB4, 0x01, 0x0F, 
  0xC0, 0x3F
};

exp

# 倒序板子
def main():
    arr = "AE81BAC1F0950A5414"  # 定义字符串
    length = len(arr)  # 获取字符串长度

    # 使用for循环反向打印字符串的前半部分
    for i in range(length // 2):
        print(arr[length - 2 * i - 2], end='')  # 打印字符,并使用空字符串''作为分隔符
        print(arr[length - 2 * i - 1], end='')

    print()  # 打印换行符

# 调用主函数
if __name__ == "__main__":
    main()
    
 # CRC32板子
secret = [0x540A95F0C1BA81AE,0xF8844E52E24A0314,0x9FD988F98143EC9,0x3FC00F01B405AD5E]
key = 0x71234EA7D92996F5
flag = ""

for s in secret:
    for i in range(255):
        sign = s & 1  
        if sign == 1:
            s ^= key
        s //= 2
        # 防止负值除2,溢出为正值
        if sign == 1:
            s |= 0x8000000000000000  
    j = 0
    while j < 8:
        flag += chr(s & 0xFF) 
        s >>= 8
        j += 1
print(flag)

quite_easy(275)

目测是一个TLS

花指令去掉了

如下

.text:                 nop
.text:00407C83                 nop
.text:00407C84                 nop
.text:00407C85                 nop
.text:00407C86                 nop
.text:00407C87                 nop
.text:00407C88                 nop
.text:00407C89                 nop
.text:00407C8A                 nop
.text:00407C8B                 nop
.text:00407C8C                 nop
.text:00407C8D                 nop
.text:00407C8E                 nop
.text:00407C8F                 nop
.text:00407C90                 nop
基于rand的一个简单加密 
int __cdecl sub_40A5A0(char *Str, int a2)
{
  int v2; // eax
  char v3; // al
  char v4; // si
  char v5; // si
  char v6; // di
  _BYTE *v7; // eax
  char v8; // si
  char v9; // si
  char v10; // di
  _BYTE *v11; // eax
  const char *v12; // eax
  _BYTE *v14; // [esp+10h] [ebp-158h]
  int v15; // [esp+18h] [ebp-150h]
  int m; // [esp+E4h] [ebp-84h]
  int k; // [esp+F0h] [ebp-78h]
  int j; // [esp+FCh] [ebp-6Ch]
  int i; // [esp+108h] [ebp-60h]
  char v20[36]; // [esp+114h] [ebp-54h] BYREF
  char v21[32]; // [esp+138h] [ebp-30h] BYREF
  int v22; // [esp+164h] [ebp-4h]

  __CheckForDebuggerJustMyCode(&unk_41A036);
  sub_40111D(Str);
  v22 = 1;
  sub_40111D(&::Str);
  v2 = sub_401663(v21);
  srand(v2 + 89);
  for ( i = 0; i < 16; ++i )
  {
    v3 = rand();
    sub_4013E3(v3);
  }
  if ( sub_401663(v21) != 48 )
    exit(99);
  for ( j = 0; j < 16; ++j )
  {
    v4 = *sub_4010DC(j);
    v5 = *sub_4010DC(j + 32) ^ v4;
    v6 = *sub_4010DC(j);
    v7 = sub_4010DC(j + 32);
    sub_4013E3(~(*v7 & v6) & v5);
  }
  for ( k = 16; k < 32; ++k )
  {
    v8 = *sub_4010DC(k);
    v9 = *sub_4010DC(k - 16) ^ v8;
    v10 = *sub_4010DC(k);
    v11 = sub_4010DC(k - 16);
    sub_4013E3(~(*v11 & v10) & v9);
  }
  for ( m = 0; m < 32; ++m )
  {
    v14 = sub_4010DC(m);
    *v14 -= *(m + a2);
  }
  sub_401460();
  v12 = sub_4014E7(v20);
  v15 = strcmp(v12, Str2);
  LOBYTE(v22) = 0;
  sub_401357(v20);
  v22 = -1;
  sub_401357(v21);
  return v15;
}

考点基本就是antidebug 动静结合得到加密流程

rand得到ke后 前16个与其异或 后16个和前16个异或进行

exp

#include <stdlib.h> // For srand() and rand()
#include <stdio.h>

int main() {
    int ke[33] = {0};
	int temp[16];
    for(int k = 0; k < 255; k++) {
        srand(k + 89);
        for(int i = 0; i < 16; ++i) {
            ke[i] = rand() & 0xff;

        }

        char flag[33] = "flag{ed1d665e6516a37ab09f0b7a40}";

        int data[33] = {0x80, 0xD3, 0x6F, 0xFF, 0x15, 0x03, 0x98, 0x8C, 0xB4, 0x5B,
                         0x96, 0xC0, 0x59, 0xAC, 0x18, 0xDF, 0x2D, 0xCE, 0x3F, 0xFB,
                         0xC4, 0xED, 0xD8, 0xD2, 0xA8, 0x2D, 0xF8, 0x23, 0x9F, 0x22,
                         0x25, 0xCE};

        for(int i = 0; i < 32; i++) {
            data[i] += flag[i];
        }
        if((data[0] ^ ke[0]) == 87) {
 
            for(int i = 0; i < 16; i++) {

                int flag1 = (data[i] ^ ke[i % 16]) & 0xff;

                int flag2 = data[i+16]^flag1;
                printf("%c", flag1);
                printf("\n2:%c", flag2);

            }
	}
        }

    
    return 0;

}
 

然后手动整理一下 WKCTF{08898c40064d1fc4836db94fe}

ai

how_to_encrypt

import torch
import torch.nn as nn

# 读取 ciphertext.txt 中的内容并转换为张量
def read_ciphertext(file_path):
    with open(file_path, 'r') as f:
        lines = f.readlines()
    data = []
    for line in lines:
        data.append([float(x) for x in line.split()])
    return torch.tensor(data)

# 定义网络结构
class Net(nn.Module):
    def __init__(self, n):
        super(Net, self).__init__()
        self.linear = nn.Linear(n, n * n)
        self.conv = nn.Conv2d(1, 1, (2, 2), stride=1, padding=1)

    def forward(self, x):
        x = self.linear(x)
        x = x.view(1, 1, n, n)
        x = self.conv(x)
        return x

# 加载 ciphertext.txt 和 model.pth
ciphertext = read_ciphertext('ciphertext.txt')
n = int(ciphertext.shape[-1])  # 假设最后一维是 n
ciphertext = ciphertext.view(1, 1, n, n)

# 确保n与保存的模型一致
n = 47  # 根据错误信息设置为47

# 初始化网络
mynet = Net(n)
mynet.load_state_dict(torch.load('model.pth'))

# 定义一个可优化的输入变量
flag_tensor = torch.randn(n, requires_grad=True, dtype=torch.float32)

# 优化器
optimizer = torch.optim.Adam([flag_tensor], lr=0.1)

# 目标输出
target_output = ciphertext

# 迭代优化输入
for epoch in range(10000):
    optimizer.zero_grad()
    output = mynet(flag_tensor)
    loss = nn.MSELoss()(output, target_output)
    loss.backward()
    optimizer.step()
    
    if epoch % 1000 == 0:
        print(f'Epoch {epoch}, Loss: {loss.item()}')

# 获取优化后的输入
optimized_flag = flag_tensor.detach().numpy()

# 将优化后的输入转换回字符
flag = ''.join([chr(int(round(x))) for x in optimized_flag])
print("Recovered flag:", flag)

修改一下部分细节最后确认一下

flag{Mi_muhe_mosi!Mi_muhe_mita,mita_movo_lata!}

苏ICP备2024067700号 | 苏公网安备32098202000238号