ReversingKr-wp(4)

Twist1

在这里插入图片描述

加了某种奇怪的壳, 应该是专有壳, 需要手动脱壳, ReadMe说了要在x86下运行, 所以丢进52pojie的xp虚拟机里调试
一上来就加了反调试, 下断点后在call Twist1.00407059处会出错, 确实是题如其名, 很扭曲, 上了专有壳, 反调试, SMC, 函数校验, 代码混淆, 配置跟实际的逆向保护软件比较接近了.
在这里插入图片描述

解法就是见招拆招, 单步跟踪对每一个加密保护逐一破解
单步跟踪不下断, 调试可以发现0x00407059是关键函数, 跟进去, 发现下面这四条指令是SMC运行时解密代码, F4出来解密之后继续跟, 需要经过总共4个解密指令段, 最后可以恢复出函数主体逻辑
在这里插入图片描述

抵达OEP, 此时可以dump出来脱壳的程序方便之后重载
在这里插入图片描述
往下走, 发现call 0x00401270时程序会执行输入操作, 输入后会卡主, 则跟进去, 发现有SetUnhandledExceptionFilter 异常捕获函数, 属于反调试机制, nop掉判断条件adc dl,byte ptr ds:[edx]继续调试
在这里插入图片描述
接下来就定位到程序的关键逻辑
在这里插入图片描述
显然字符串处理函数在0x004012C6, 跟进去又经过一段SMC解密代码, 最后来到处理函数, 这里可以dump出来用IDA分析, 直接读汇编也问题不大, 锻炼基本功
在这里插入图片描述
这里会校验16字节的数据来判断函数完整性, 是检测系统版本的一步
在这里插入图片描述
接下来有3个调试, nop掉失败条件继续跟
在这里插入图片描述又来一个getthreadcontext反调试, nop掉失败跳转继续跟
在这里插入图片描述
接着是硬件断点反调试, 也是nop无脑通过
在这里插入图片描述

最后来到处理逻辑 (finally
而且还加了代码混淆, 控制流非常混乱, 需要每个call都跟进去分析一遍
一路跟一路分析:
arr[0]循环右移6位,检查与0x49相等
arr[2]异或0x77, 检查与0x35相等
在这里插入图片描述
arr[1]与0x20异或,检查与0x69相等
arr[3]与0x21异或,检查与0x64相等
arr[4]与0x46异或,检查与0x8相等
arr[5]循环左移4位,检查与0x14相等

写逆

#include <stdlib.h>
#include <stdio.h>

int main() {
    char valid[] = {0x49, 0x69, 0x35, 0x64, 0x08, 0x14};
    char arr[7] = {0};
    arr[0] = valid[0] << 6 | valid[0] >> 2;
    arr[1] = valid[1] ^ 0x20;
    arr[2] = valid[2] ^ 0x77;
    arr[3] = valid[3] ^ 0x21;
    arr[4] = valid[4] ^ 0x46;
    arr[5] = valid[5] >> 4 | valid[5] << 4;
    
    for (int i = 0; i < 7; ++i) {
        printf("%c", arr[i]);
    }
    printf("\n");
}

完成! 前后调试了3h, 真的够变态, 大量反调试, SMC, 还检测函数完整性, 最后在核心代码处加了控制流混淆和花指令, 虽说很折磨但是逆出来还是可以学到很多技术
(逆向, 最重要的还是耐心

Easy ELF

拿到一个zip文件, 解压发现出错, 怀疑是文件格式不对
放到kali, file一下
在这里插入图片描述

是ELF32位文件
拖入IDA, 反汇编后扫一遍各个函数, 找到一个可能是关键函数

_BOOL4 sub_8048451()
{
  if ( byte_804A021 != 49 )
    return 0;
  byte_804A020 ^= 0x34u;
  byte_804A022 ^= 0x32u;
  byte_804A023 ^= 0x88u;
  if ( byte_804A024 != 88 )
    return 0;
  if ( byte_804A025 )
    return 0;
  if ( byte_804A022 != 124 )
    return 0;
  if ( byte_804A020 == 120 )
    return byte_804A023 == -35;
  return 0;
}

读一下main函数汇编, 先后call了sub_8038434, sub_8048451之后是分支到wrong和correct, 说明这两个函数就是关键函数

写出脚本

Byte21 = 49
Byte20 = 120 ^ 0x34
Byte22 = 124 ^ 0x32
Byte23 = (-35 & 0xff) ^ 0x88
Byte24 = 88
Byte25 = 0
flag = chr(Byte20) + chr(Byte21) + chr(Byte22) + chr(Byte23) + chr(Byte24) + chr(Byte25)
print(flag)

WindowsKernel

在这里插入图片描述

无壳, 拖进IDA, 程序结构不是很复杂, 也没有应用加密, 可以看到sub_401110函数中有关键字符串

 HWND __thiscall sub_401110(HWND hDlg)
{
  HWND result; // eax
  HWND v3; // eax
  HWND v4; // eax
  HWND v5; // eax
  WCHAR String[256]; // [esp+8h] [ebp-204h] BYREF

  GetDlgItemTextW(hDlg, 1003, String, 512);
  if ( lstrcmpW(String, L"Enable") )
  {
    result = (HWND)lstrcmpW(String, L"Check");
    if ( !result )
    {
      if ( sub_401280(0x2000) == 1 )
        MessageBoxW(hDlg, L"Correct!", L"Reversing.Kr", 0x40u);
      else
        MessageBoxW(hDlg, L"Wrong", L"Reversing.Kr", 0x10u);
      SetDlgItemTextW(hDlg, 1002, &word_4021F0);
      v5 = GetDlgItem(hDlg, 1002);
      EnableWindow(v5, 0);
      result = (HWND)SetDlgItemTextW(hDlg, 1003, L"Enable");
    }
  }
  else if ( sub_401280(4096) )
  {
    v3 = GetDlgItem(hDlg, 1002);
    EnableWindow(v3, 1);
    SetDlgItemTextW(hDlg, 1003, L"Check");
    SetDlgItemTextW(hDlg, 1002, &word_4021F0);
    v4 = GetDlgItem(hDlg, 1002);
    result = SetFocus(v4);
  }
  else
  {
    result = (HWND)MessageBoxW(hDlg, L"Device Error", L"Reversing.Kr", 0x10u);
  }
  return result;
}

进入sub_401280分析

int __usercall sub_401280@<eax>(HWND a1@<edi>, DWORD dwIoControlCode)
{
  HANDLE v2; // esi
  int result; // eax
  DWORD BytesReturned; // [esp+4h] [ebp-8h] BYREF
  int OutBuffer; // [esp+8h] [ebp-4h] BYREF

  v2 = CreateFileW(L"\\\\.\\RevKr", 0xC0000000, 0, 0, 3u, 0, 0);
  if ( v2 == (HANDLE)-1 )
  {
    MessageBoxW(a1, L"[Error] CreateFile", L"Reversing.Kr", 0x10u);
    result = 0;
  }
  else if ( DeviceIoControl(v2, dwIoControlCode, 0, 0, &OutBuffer, 4u, &BytesReturned, 0) )
  {
    CloseHandle(v2);
    result = OutBuffer;
  }
  else
  {
    MessageBoxW(a1, L"[Error] DeviceIoControl", L"Reversing.Kr", 0x10u);
    result = 0;
  }
  return result;
}

result结果与DeviceIoControl函数相关, 这是一个WinKer.sys的函数, 跟windows驱动相关, 分析sys文件

NTSTATUS __stdcall DriverEntry(_DRIVER_OBJECT *DriverObject, PUNICODE_STRING RegistryPath)
{
  NTSTATUS result; // eax
  int v3; // edi
  PDEVICE_OBJECT v4; // ecx
  char *v5; // et1
  char *v6; // et1
  char *v7; // et1
  char v8; // al
  struct _KDPC *v9; // esi
  char *v10; // et1
  struct _UNICODE_STRING DestinationString; // [esp+Ch] [ebp-134h] BYREF
  union _LARGE_INTEGER Interval; // [esp+14h] [ebp-12Ch] BYREF
  PDEVICE_OBJECT DeviceObject; // [esp+1Ch] [ebp-124h] BYREF
  PVOID P; // [esp+20h] [ebp-120h]
  CCHAR Number[4]; // [esp+24h] [ebp-11Ch]
  struct _OSVERSIONINFOW VersionInformation; // [esp+28h] [ebp-118h] BYREF

  DbgSetDebugFilterState(0x65u, 3u, 1u);
  DbgPrint("Driver Load!! \n");
  DriverObject->DriverUnload = (PDRIVER_UNLOAD)sub_1131C;
  dword_13030 = 0;
  VersionInformation.dwOSVersionInfoSize = 276;
  if ( RtlGetVersion(&VersionInformation) )
  {
    MajorVersion = VersionInformation.dwMajorVersion;
    MinorVersion = VersionInformation.dwMinorVersion;
  }
  else
  {
    PsGetVersion(&MajorVersion, &MinorVersion, 0, 0);
  }
  RtlInitUnicodeString(&DestinationString, "\\");
  P = (PVOID)IoCreateDevice(DriverObject, 4u, &DestinationString, 0x22u, 0, 0, &DeviceObject);
  if ( (int)P >= 0 )
  {
    RtlInitUnicodeString(&SymbolicLinkName, L"\\DosDevices\\RevKr");
    v3 = IoCreateSymbolicLink(&SymbolicLinkName, &DestinationString);
    if ( v3 >= 0 )
    {
      v4 = DeviceObject;
      DriverObject->MajorFunction[14] = (PDRIVER_DISPATCH)sub_11288;
      DriverObject->MajorFunction[0] = (PDRIVER_DISPATCH)sub_112F8;
      DriverObject->MajorFunction[2] = (PDRIVER_DISPATCH)sub_112F8;
      *(_DWORD *)v4->DeviceExtension = 0;
      SystemArgument2 = DeviceObject->DeviceExtension;
      *(_DWORD *)SystemArgument2 = DeviceObject;
      v5 = *(char **)&KeNumberProcessors;
      ::P = ExAllocatePool(NonPagedPool, 4 * *v5);
      KeInitializeDpc(&DeviceObject->Dpc, sub_11266, DeviceObject);
      v6 = *(char **)&KeNumberProcessors;
      P = ExAllocatePool(NonPagedPool, 32 * *v6);
      if ( P )
      {
        v7 = *(char **)&KeNumberProcessors;
        Interval.QuadPart = -10000000i64;
        v8 = *v7;
        Number[0] = 0;
        if ( v8 > 0 )
        {
          do
          {
            v9 = (struct _KDPC *)((char *)P + 32 * Number[0]);
            KeInitializeDpc(v9, sub_113E8, 0);
            KeSetTargetProcessorDpc(v9, Number[0]);
            KeInsertQueueDpc(v9, 0, 0);
            KeDelayExecutionThread(0, 0, &Interval);
            v10 = *(char **)&KeNumberProcessors;
            ++Number[0];
          }
          while ( Number[0] < *v10 );
        }
        ExFreePoolWithTag(P, 0);
      }
      result = 0;
    }
    else
    {
      IoDeleteDevice(DriverObject->DeviceObject);
      result = v3;
    }
  }
  else
  {
    DbgPrint("IoCreateDevice Error\n");
    result = (NTSTATUS)P;
  }
  return result;
}

根据Windows系统编程经验, DriverObject->MajorFunction[14] = (PDRIVER_DISPATCH)sub_11288;以及KeInitializeDpc会开启一个thread去执行目标函数, 跟进去分析sub_11288

int __stdcall sub_11288(int a1, PIRP Irp)
{
  int v2; // edx
  struct _IRP *v3; // eax

  v2 = *(_DWORD *)(Irp->Tail.Overlay.PacketType + 12);
  v3 = Irp->AssociatedIrp.MasterIrp;
  if ( v2 == 4096 ) // 0x1000
  {
    *(_DWORD *)&v3->Type = 1;
    dword_13030 = 1;
    dword_13034 = 0;
    dword_13024 = 0;
    dword_1300C = 0;
  }
  else if ( v2 == 0x2000 )
  {
    dword_13030 = 0;
    *(_DWORD *)&v3->Type = dword_13024;
  }
  Irp->IoStatus.Status = 0;
  Irp->IoStatus.Information = 4;
  IofCompleteRequest(Irp, 0);
  return 0;
}

根据WindowsKernel.exe的判断函数sub_401280(0x2000) == 1, 所以这里传进来的参数是0x2000, 只考察v2 == 0x2000这一个分支的逻辑, dword_13030会设置为0, 以及设置lrp. 接着看sub_11266函数

void __stdcall sub_11266(struct _KDPC *Dpc, PVOID DeferredContext, PVOID SystemArgument1, PVOID SystemArgument2)
{
  char v4; // al

  v4 = READ_PORT_UCHAR((PUCHAR)0x60);
  sub_111DC(v4);
}

继续根据Windows系统编程经验, 这个驱动函数是从端口0x60也就是键盘读入参数保存在v4, 分析sub_111DC和里面的跟result相关的函数

int __stdcall sub_111DC(char a1)
{
  int result; // eax
  bool v2; // zf

  result = 1;
  if ( dword_1300C != 1 )
  {
    switch ( dword_13034 )
    {
      case 0:
      case 2:
      case 4:
      case 6:
        goto LABEL_3;
      case 1:
        v2 = a1 == -91;
        goto LABEL_6;
      case 3:
        v2 = a1 == -110;
        goto LABEL_6;
      case 5:
        v2 = a1 == -107;
LABEL_6:
        if ( !v2 )
          goto LABEL_7;
LABEL_3:
        ++dword_13034;
        break;
      case 7:
        if ( a1 == -80 )
          dword_13034 = 100;
        else
LABEL_7:
          dword_1300C = 1;
        break;
      default:
        result = sub_11156(a1);
        break;
    }
  }
  return result;
}

// continue analysis sub_11156 and next function in it
int __stdcall sub_11156(char a1)
{
  int result; // eax
  bool v2; // zf
  char v3; // [esp+8h] [ebp+8h]

  v3 = a1 ^ 0x12;
  result = dword_13034 - 100;
  switch ( dword_13034 )
  {
    case 'd':
    case 'f':
    case 'h':
    case 'j':
      goto LABEL_2;
    case 'e':
      v2 = v3 == -78;
      goto LABEL_4;
    case 'g':
      v2 = v3 == -123;
      goto LABEL_4;
    case 'i':
      v2 = v3 == -93;
LABEL_4:
      if ( !v2 )
        goto LABEL_5;
LABEL_2:
      ++dword_13034;
      break;
    case 'k':
      if ( v3 == -122 )
        dword_13034 = 200;
      else
LABEL_5:
        dword_1300C = 1;
      break;
    default:
      result = sub_110D0(v3);
      break;
  }
  return result;
}

int __stdcall sub_110D0(char a1)
{
  int result; // eax
  char v2; // cl
  bool v3; // zf

  result = dword_13034 - 200;
  v2 = a1 ^ 5;
  switch ( dword_13034 )
  {
    case 200:
    case 202:
    case 204:
    case 206:
      goto LABEL_2;
    case 201:
      v3 = v2 == -76;
      goto LABEL_4;
    case 203:
    case 205:
      v3 = v2 == -113;
LABEL_4:
      if ( v3 )
        goto LABEL_2;
      goto LABEL_10;
    case 207:
      if ( v2 != -78 )
        goto LABEL_10;
      dword_13024 = 1;
LABEL_2:
      ++dword_13034;
      break;
    case 208:
      dword_13024 = 0;
LABEL_10:
      dword_1300C = 1;
      break;
    default:
      return result;
  }
  return result;
}

dword_13034 = 0初值为0, 所以结合scan code对照表可以分析出使得满足判断条件时的键盘输入字符串
[0xA5, 0x92, 0x95, 0xB0]
[0xB2, 0x85, 0xA3, 0x86] xor 0x12
[0xB4, 0x8F, 0x8F, 0xB2] xor 0x12 xor 0x05

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值