UPX+地址偏移间接操作

脱壳直接给一个假的flag

int __cdecl main(int argc, const char **argv, const char **envp)
{
  char v4[1024]; // [esp+4h] [ebp-804h] BYREF
  _BYTE v5[1024]; // [esp+404h] [ebp-404h] BYREF

  memset(v5, 0, sizeof(v5));
  memset(v4, 0, sizeof(v4));
  printf("please input code:");
  scanf("%s", v5);
  sub_401000(v5);
  if ( !strcmp(v4, "DDCTF{reverseME}") )
    printf("You've got it!!%s\n", v4);
  else
    printf("Try again later.\n");
  return 0;
}

看看函数 发现是一个逐字节查表替换 那我们就应该找一下这个所替换的表在哪里

unsigned int __cdecl sub_401000(const char *a1)
{
  _BYTE *v1; // ecx
  unsigned int v2; // edi
  unsigned int result; // eax
  int v4; // ebx

  v2 = 0;
  result = strlen(a1);
  if ( result )
  {
    v4 = a1 - v1;
    do
    {
      *v1 = byte_402FF8[(char)v1[v4]];
      ++v2;
      ++v1;
      result = strlen(a1);
    }
    while ( v2 < result );
  }
  return result;
}
  1. 看原理 定位表

程序使用了一个带偏移的可打印 ASCII 反转表 在sub_401000 中 关键汇编是

00401020  movsx   eax, byte ptr [ebx+ecx]
00401024  mov     dl, byte ptr [eax+402FF8h]
0040102A  mov     eax, ebp
0040102C  mov     byte ptr [ecx], dl

这还是容易看出来的 下面这个真不容易一眼看出来

.text:00401020                 movsx   eax, byte ptr [ebx+ecx]
.text:00401024                 mov     dl, ds:byte_402FF8[eax]
.text:0040102A                 mov     eax, ebp
.text:0040102C                 mov     [ecx], dl

但都是可以简化为:

output[i] = *(char *)(0x402FF8 + input[i]);

所以我们就知道输入字符被直接当作索引使用 同时我们还是不知道表在哪里 那我们输入的字符是不是都是可打印字符 那范围为

0x20 ~ 0x7E

所以真正会被访问的内存范围是

最小地址:0x402FF8 + 0x20 = 0x403018
最大地址:0x402FF8 + 0x7E = 0x403076

因此,真正的数据表位于

0x403018 ~ 0x403076

长度为

0x7E - 0x20 + 1 = 0x5F = 95

个字节

那我们定位还是定位到

.data:00403018 aZyxwvutsrqponm db '~}|{zyxwvutsrqponmlkjihgfedcba`_^]\[ZYXWVUTSRQPONMLKJIHGFEDCBA@?>'
.data:00403059                 db '=<;:9876543210/.-,+*)(',27h,'&%$#"! ',0

这个就是表

  1. 邪修方法

由于byte_402FF8点击进去发现是空的 调试也调试不行 索性下面就有一个看着像表的 拿过来一看 还真对了 哈哈哈哈

image

exp

table = b"~}|{zyxwvutsrqponmlkjihgfedcba`_^]\\[ZYXWVUTSRQPONMLKJIHGFEDCBA@?>=<;:9876543210/.-,+*)('&%$#\"! "
target = b"DDCTF{reverseME}"

code = bytes(
    table.index(char) + 0x20
    for char in target
)
print('flag{',end='')
print(code.decode(),end = '')
print('}')

flag

flag{ZZ[JX#,9(9,+9QY!}