selph
selph
发布于 2024-05-09 / 32 阅读
0
0

[HTB] re - Simple Encryptor

analysis:

int __fastcall main(int argc, const char **argv, const char **envp)
{
  char v3; // al
  char tmp_byte; // [rsp+7h] [rbp-39h]
  unsigned int seed[2]; // [rsp+8h] [rbp-38h] BYREF
  __int64 idx; // [rsp+10h] [rbp-30h]
  FILE *stream; // [rsp+18h] [rbp-28h]
  size_t size; // [rsp+20h] [rbp-20h]
  void *buffer; // [rsp+28h] [rbp-18h]
  FILE *s; // [rsp+30h] [rbp-10h]
  unsigned __int64 v12; // [rsp+38h] [rbp-8h]

  v12 = __readfsqword(0x28u);
  stream = fopen("flag", "rb");
  fseek(stream, 0LL, 2);
  size = ftell(stream);
  fseek(stream, 0LL, 0);
  buffer = malloc(size);
  fread(buffer, size, 1uLL, stream);
  fclose(stream);
  seed[0] = time(0LL);
  srand(seed[0]);
  for ( idx = 0LL; idx < (__int64)size; ++idx )
  {
    *((_BYTE *)buffer + idx) ^= rand();
    v3 = rand();
    tmp_byte = *((_BYTE *)buffer + idx);
    seed[1] = v3 & 7;
    *((_BYTE *)buffer + idx) = __ROL1__(tmp_byte, v3 & 7);
  }
  s = fopen("flag.enc", "wb");
  fwrite(seed, 1uLL, 4uLL, s);
  fwrite(buffer, 1uLL, size, s);
  fclose(s);
  return 0;
}

我们有一个加密结果enc,可以逆向看到加密过程,目标逆向还原加密内容

要是觉得for看着乱七八糟的,看反汇编看过程更清晰:

.text:0000000000001350
.text:0000000000001350 loc_1350:                               ; CODE XREF: main+13F↓j
.text:0000000000001350                 call    _rand
.text:0000000000001355                 movzx   ecx, al         ; one random num
.text:0000000000001358                 mov     rdx, [rbp+idx]
.text:000000000000135C                 mov     rax, [rbp+buffer]
.text:0000000000001360                 add     rax, rdx
.text:0000000000001363                 movzx   eax, byte ptr [rax] ; get a byte
.text:0000000000001366                 mov     edx, eax
.text:0000000000001368                 mov     eax, ecx
.text:000000000000136A                 mov     ecx, edx
.text:000000000000136C                 xor     ecx, eax        ; a byte xor random num
.text:000000000000136E                 mov     rdx, [rbp+idx]
.text:0000000000001372                 mov     rax, [rbp+buffer]
.text:0000000000001376                 add     rax, rdx
.text:0000000000001379                 mov     edx, ecx
.text:000000000000137B                 mov     [rax], dl       ; save the res in this idx
.text:000000000000137D                 call    _rand
.text:0000000000001382                 and     eax, 7          ; next random num, less than 7
.text:0000000000001385                 mov     ecx, eax
.text:0000000000001387                 mov     rdx, [rbp+idx]
.text:000000000000138B                 mov     rax, [rbp+buffer]
.text:000000000000138F                 add     rax, rdx
.text:0000000000001392                 movzx   eax, byte ptr [rax]
.text:0000000000001395                 movzx   eax, al         ; get the same byte
.text:0000000000001398                 mov     rsi, [rbp+idx]
.text:000000000000139C                 mov     rdx, [rbp+buffer]
.text:00000000000013A0                 add     rdx, rsi
.text:00000000000013A3                 mov     [rbp+tmp_byte], al
.text:00000000000013A6                 mov     [rbp+random_num2], ecx
.text:00000000000013A9                 movzx   eax, [rbp+tmp_byte]
.text:00000000000013AD                 mov     esi, eax
.text:00000000000013AF                 mov     eax, [rbp+random_num2]
.text:00000000000013B2                 mov     ecx, eax
.text:00000000000013B4                 rol     sil, cl         ; 循环左移随机数位
.text:00000000000013B7                 mov     eax, esi
.text:00000000000013B9                 mov     [rdx], al       ; 保存起来
.text:00000000000013BB                 add     [rbp+idx], 1
.text:00000000000013C0

这里就是基础的算法反着写就行,正常流程:

  1. 取1字节,和随机数1异或
  2. 随机数2&7(取一个小于7的值,反正超过8就会变原状,所以有效结果就是对7取余)
  3. 循环左移

反过来即可拿到flag

exp:


#include <stdio.h>
unsigned char hexData[32] = {
    0x5A, 0x35, 0xB1, 0x62, 0x00, 0xF5, 0x3E, 0x12, 0xC0, 0xBD, 0x8D, 0x16, 0xF0, 0xFD, 0x75, 0x99,
    0xFA, 0xEF, 0x39, 0x9A, 0x4B, 0x96, 0x21, 0xA1, 0x43, 0x16, 0x23, 0x71, 0x65, 0xFB, 0x27, 0x4B
};


unsigned char ror(unsigned char val, int shift) {
    return (val >> shift) | (val << (8 - shift));
}

int main() {
    unsigned int seed = *(unsigned int*)hexData;
    unsigned char *enc = &hexData[4];
    unsigned char dec[28+1]={0};
    printf("Seed: %08x\n", seed);
    srand(seed);
    for(int i = 0; i < 28; i++) {
        unsigned char random1 = rand() & 0xff;
        unsigned char random2 = rand() & 7;
        dec[i] = ror(enc[i], random2);
        dec[i] ^= random1;
        printf("%02x: %02x %02x - %02x\n",enc[i], random1, random2,dec[i]);
    }
    printf("%s\n", dec);
}

需要在linux下编译,Windows和Linux的rand运行结果是不一样的,程序用的Linux我们也得用Linux

summary:

  • 小细节:rand()在相同种子情况下,不同平台下运行结果不同

评论