首页
社区
课程
招聘
[原创]SWPU2019_EasiestRe双进程保护(子进程调试父进程逆向分析)
发表于: 2024-6-6 01:12 4011

[原创]SWPU2019_EasiestRe双进程保护(子进程调试父进程逆向分析)

2024-6-6 01:12
4011

加密手段:
数据结构分析:
逆向分析中的问题:
获得flag:

题目类型:
[[双进程保护]]
smc代码自修改
[[结构化异常SEH处理机制]]
Interrupt 3(03中断检测)
[[Merkle-Hellman背包加密]]


简介:
wp借鉴:
BUUCTF [SWPU2019]EasiestRe_皮皮蟹!的博客-CSDN博客
[SWPU2019]EasiestRe-cnblog - 自我摧残之策 - 博客园 (cnblogs.com)
[SWPU2019]EasiestRe - 编程猎人 (programminghunter.com)
[buuctf.reverse] 121-125_2021gkctf somuchcode-CSDN博客
446K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6%4N6%4N6Q4x3X3g2U0L8X3u0D9L8$3N6K6i4K6u0W2j5$3!0E0i4K6u0r3K9r3q4J5L8h3!0F1K9h3y4S2x3e0q4Q4x3V1k6H3i4K6u0r3x3e0x3#2x3U0f1$3y4U0y4Q4x3X3g2Z5N6r3#2D9
f63K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6%4N6%4N6Q4x3X3f1#2x3Y4m8G2K9X3W2W2i4K6u0W2j5$3&6Q4x3V1k6@1K9s2u0W2j5h3c8Q4x3X3b7I4y4e0R3H3y4U0V1I4i4K6u0V1x3g2)9J5k6o6q4Q4x3X3g2Z5N6r3#2D9i4K6t1K6y4o6p5@1y4o6l9H3z5e0q4Q4y4h3k6Q4y4f1u0K6N6%4m8#2i4K6g2p5i4K6u0V1k6h3q4K6K9h3g2K6N6s2u0W2
017K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6%4N6%4N6Q4x3X3g2U0L8X3u0D9L8$3N6K6i4K6u0W2j5$3!0E0i4K6u0r3L8r3!0J5k6s2c8A6j5h3&6I4K9i4W2A6i4K6u0r3j5i4u0@1K9h3y4D9k6i4y4Q4x3V1j5I4y4U0b7#2y4U0j5J5y4W2)9J5k6h3S2@1L8h3H3`.

整体代码逆向分析:

整体父程序分析!

这里就是程序的输入入口了,但是真实的代码要运行以后通过触发int 3断点后才会出现!

根据父进程代码可知当程序中int 3 下面存在6个nop时将v16的数据写入!

成功写入!!

继续观察该函数发现:

继续一步步跟进函数发现!
sub_40247D(Str, v2, v1); -》sub_408860(Str, a2, a3);-》sub_40460B(a2, v10);
发现sub_40460B(a2, v10);这个函数内部也存在一个int 3 且下面的数据nop一共有30个!所以继续使用idapython脚本将程序patch!

成功patch

继续向下看:

分析一下sub_F7384B(v0); // 最后的函数,里面同样存在int 3,但是父进程只是发出了报错异常

为了不动态调试直接手动加一条jmp指令就可以了!!!

修改成功后的伪代码!

上面是加密过程!

下面是解密过程:

下面是分析背包解密了:


3. 获取私钥

解密脚本:

最后还有一个异或运算:

int __cdecl main_0(int argc, const char **argv, const char **envp)
{
  PVOID lpBaseAddress; // [esp+18h] [ebp-558h]                    
...
  if ( IsDebuggerPresent() )   // 监测到调试状态,进入分支
  {
    falseflagfun();// 这里是真正的加密解密函数位置,由于这个程序是双进程保护,父进程会对程序进行修改,直接手动修改就可以代替父进程的运行,直接动态调试
    return 0;
  }
  else                                          // 正常启动进入普通分支
  {
    GetStartupInfoA(&StartupInfo);
    GetModuleFileNameA(0, Filename, 0x104u);
    if ( CreateProcessA(Filename, 0, 0, 0, 0, 3u, 0, 0, &StartupInfo, &ProcessInformation) )// 创建子进程并检测断点
    {
      v5 = 1;
LABEL_6:
      while ( v5 )
      {
        dwContinueStatus = 0x10002;
        WaitForDebugEvent(&DebugEvent, 0xFFFFFFFF);// 等待debug时间
        switch ( DebugEvent.dwDebugEventCode )
        {
          case 1u:
            if ( DebugEvent.u.Exception.ExceptionRecord.ExceptionCode == 0x80000003 )// 表示调试器断点异常int 3触发
            {
              v8 = 1;
              dwContinueStatus = 65538;         // 将变量 dwContinueStatus 的值设置为 65538。这可能是一个用于指示调试器如何继续执行的状态码
              lpBaseAddress = DebugEvent.u.Exception.ExceptionRecord.ExceptionAddress;// 获取发出异常的地址
              ReadProcessMemory(                // 读取异常位置的0x23个字节,存储到buffer里
                ProcessInformation.hProcess,
                DebugEvent.u.Exception.ExceptionRecord.ExceptionAddress,
                Buffer,
                0x23u,
                NumberOfBytesRead);             // 实际读取到的字节数:NumberOfBytesRead
              if ( NumberOfBytesRead[0] )
              {
                for ( i = 1; i < 35 && Buffer[i] == 0x90; ++i )// 检测读取到的内存有多少个nop指令
                  ;
              }
              if ( i == 1 )
                v8 = 0;
              if ( v8 )
              {
                switch ( i )                    // nop指令数量不同处理
                {
                  case 4:                       // 如果有4位需要补则直接让eip+1继续执行
                    Context.ContextFlags = 65543;
                    hThread = OpenThread(0x1FFFFFu, 0, DebugEvent.dwThreadId);
                    if ( !GetThreadContext(hThread, &Context) )
                      goto LABEL_31;
                    ++Context.Eip;
                    if ( SetThreadContext(hThread, &Context) )
                    {
                      dwContinueStatus = 65538;
                      CloseHandle(hThread);
                    }
                    goto LABEL_33;
                  case 5:
LABEL_31:
                    ContinueDebugEvent(DebugEvent.dwProcessId, DebugEvent.dwThreadId, 0x80010001);
                    goto LABEL_6;
                  case 7:                       // 如果有7位则用v16的内容补齐
                    WriteProcessMemory(ProcessInformation.hProcess, lpBaseAddress, v16, 7u, NumberOfBytesWritten);
                    if ( NumberOfBytesWritten[0] == 7 )
                    {
                      ReadProcessMemory(ProcessInformation.hProcess, lpBaseAddress, Buffer, 7u, NumberOfBytesRead);
                      dwContinueStatus = 65538;
                    }
                    goto LABEL_33;
                  case 30:                      // 如果有30位则用v15的内容补齐
                    WriteProcessMemory(ProcessInformation.hProcess, lpBaseAddress, v15, 0x1Eu, NumberOfBytesWritten);
                    if ( NumberOfBytesWritten[0] == 30 )
                      dwContinueStatus = 65538;
                    goto LABEL_33;
                  default:
                    goto LABEL_33;
 ...
}
int __cdecl main_0(int argc, const char **argv, const char **envp)
{
  PVOID lpBaseAddress; // [esp+18h] [ebp-558h]                    
...
  if ( IsDebuggerPresent() )   // 监测到调试状态,进入分支
  {
    falseflagfun();// 这里是真正的加密解密函数位置,由于这个程序是双进程保护,父进程会对程序进行修改,直接手动修改就可以代替父进程的运行,直接动态调试
    return 0;
  }
  else                                          // 正常启动进入普通分支
  {
    GetStartupInfoA(&StartupInfo);
    GetModuleFileNameA(0, Filename, 0x104u);
    if ( CreateProcessA(Filename, 0, 0, 0, 0, 3u, 0, 0, &StartupInfo, &ProcessInformation) )// 创建子进程并检测断点
    {
      v5 = 1;
LABEL_6:
      while ( v5 )
      {
        dwContinueStatus = 0x10002;
        WaitForDebugEvent(&DebugEvent, 0xFFFFFFFF);// 等待debug时间
        switch ( DebugEvent.dwDebugEventCode )
        {
          case 1u:
            if ( DebugEvent.u.Exception.ExceptionRecord.ExceptionCode == 0x80000003 )// 表示调试器断点异常int 3触发
            {
              v8 = 1;
              dwContinueStatus = 65538;         // 将变量 dwContinueStatus 的值设置为 65538。这可能是一个用于指示调试器如何继续执行的状态码
              lpBaseAddress = DebugEvent.u.Exception.ExceptionRecord.ExceptionAddress;// 获取发出异常的地址
              ReadProcessMemory(                // 读取异常位置的0x23个字节,存储到buffer里
                ProcessInformation.hProcess,
                DebugEvent.u.Exception.ExceptionRecord.ExceptionAddress,
                Buffer,
                0x23u,
                NumberOfBytesRead);             // 实际读取到的字节数:NumberOfBytesRead
              if ( NumberOfBytesRead[0] )
              {
                for ( i = 1; i < 35 && Buffer[i] == 0x90; ++i )// 检测读取到的内存有多少个nop指令
                  ;
              }
              if ( i == 1 )
                v8 = 0;
              if ( v8 )
              {
                switch ( i )                    // nop指令数量不同处理
                {
                  case 4:                       // 如果有4位需要补则直接让eip+1继续执行
                    Context.ContextFlags = 65543;
                    hThread = OpenThread(0x1FFFFFu, 0, DebugEvent.dwThreadId);
                    if ( !GetThreadContext(hThread, &Context) )
                      goto LABEL_31;
                    ++Context.Eip;
                    if ( SetThreadContext(hThread, &Context) )
                    {
                      dwContinueStatus = 65538;
                      CloseHandle(hThread);
                    }
                    goto LABEL_33;
                  case 5:
LABEL_31:
                    ContinueDebugEvent(DebugEvent.dwProcessId, DebugEvent.dwThreadId, 0x80010001);
                    goto LABEL_6;
                  case 7:                       // 如果有7位则用v16的内容补齐
                    WriteProcessMemory(ProcessInformation.hProcess, lpBaseAddress, v16, 7u, NumberOfBytesWritten);
                    if ( NumberOfBytesWritten[0] == 7 )
                    {
                      ReadProcessMemory(ProcessInformation.hProcess, lpBaseAddress, Buffer, 7u, NumberOfBytesRead);
                      dwContinueStatus = 65538;
                    }
                    goto LABEL_33;
                  case 30:                      // 如果有30位则用v15的内容补齐
                    WriteProcessMemory(ProcessInformation.hProcess, lpBaseAddress, v15, 0x1Eu, NumberOfBytesWritten);
                    if ( NumberOfBytesWritten[0] == 30 )
                      dwContinueStatus = 65538;
                    goto LABEL_33;
                  default:
                    goto LABEL_33;
 ...
}
char Main()
{
  int v1[62]; // [esp+8h] [ebp-138h] BYREF
  char Str[56]; // [esp+100h] [ebp-40h] BYREF
  size_t v3; // [esp+138h] [ebp-8h]
 
  v3 = 0;
  j__memset(Str, 0, 0x32u);
  v1[52] = 2;
  v1[53] = 3;
  v1[54] = 7;
  v1[55] = 14;
  v1[56] = 30;
  v1[57] = 57;
  v1[58] = 120;
  v1[59] = 251;
  j__memset(v1, 0, 0xC8u);
  printf("Please Input Flag:\n");
  scanf("%s", Str);
  v3 = j__strlen(Str);
  __debugbreak();
  printf("you are too short!");
  return 0;
}
char Main()
{
  int v1[62]; // [esp+8h] [ebp-138h] BYREF
  char Str[56]; // [esp+100h] [ebp-40h] BYREF
  size_t v3; // [esp+138h] [ebp-8h]
 
  v3 = 0;
  j__memset(Str, 0, 0x32u);
  v1[52] = 2;
  v1[53] = 3;
  v1[54] = 7;
  v1[55] = 14;
  v1[56] = 30;
  v1[57] = 57;
  v1[58] = 120;
  v1[59] = 251;
  j__memset(v1, 0, 0xC8u);
  printf("Please Input Flag:\n");
  scanf("%s", Str);
  v3 = j__strlen(Str);
  __debugbreak();
  printf("you are too short!");
  return 0;
}
.text:00408AF8                 int     3               ; Trap to Debugger
.text:00408AF9                 nop
.text:00408AFA                 nop
.text:00408AFB                 nop
.text:00408AFC                 nop
.text:00408AFD                 nop
.text:00408AFE                 nop
.text:00408AFF                 push    offset aYouAreTooShort ; "you are too short!"
.text:00408B04                 call    printf
.text:00408AF8                 int     3               ; Trap to Debugger
.text:00408AF9                 nop
.text:00408AFA                 nop
.text:00408AFB                 nop
.text:00408AFC                 nop
.text:00408AFD                 nop
.text:00408AFE                 nop
.text:00408AFF                 push    offset aYouAreTooShort ; "you are too short!"
.text:00408B04                 call    printf
from idaapi import *
from idc import *
a = [0x90, 0x83, 0x7D, 0xF8, 0x18, 0x7D, 0x11]
b = 0x408AF8
for i in range(7):
    ida_bytes.patch_byte(b + i, a[i])
from idaapi import *
from idc import *
a = [0x90, 0x83, 0x7D, 0xF8, 0x18, 0x7D, 0x11]
b = 0x408AF8
for i in range(7):
    ida_bytes.patch_byte(b + i, a[i])
char Main()
{
  int v1[52]; // [esp+8h] [ebp-138h] BYREF
  int v2[10]; // [esp+D8h] [ebp-68h] BYREF
  char Str[56]; // [esp+100h] [ebp-40h] BYREF
  int len; // [esp+138h] [ebp-8h]
 
  len = 0;
  j__memset(Str, 0, 0x32u);
  v2[0] = 2;
  v2[1] = 3;
  v2[2] = 7;
  v2[3] = 14;
  v2[4] = 30;
  v2[5] = 57;
  v2[6] = 120;
  v2[7] = 251;
  j__memset(v1, 0, 0xC8u);
  printf("Please Input Flag:\n");
  scanf("%s", Str);
  len = j__strlen(Str);
  if ( len >= 24 )
  {
    sub_40247D(Str, v2, v1);
    sub_40384B(v1);
  }
  printf("you are too short!");
  return 0;
}
char Main()
{
  int v1[52]; // [esp+8h] [ebp-138h] BYREF
  int v2[10]; // [esp+D8h] [ebp-68h] BYREF
  char Str[56]; // [esp+100h] [ebp-40h] BYREF
  int len; // [esp+138h] [ebp-8h]
 
  len = 0;
  j__memset(Str, 0, 0x32u);
  v2[0] = 2;
  v2[1] = 3;
  v2[2] = 7;
  v2[3] = 14;
  v2[4] = 30;
  v2[5] = 57;
  v2[6] = 120;
  v2[7] = 251;
  j__memset(v1, 0, 0xC8u);
  printf("Please Input Flag:\n");
  scanf("%s", Str);
  len = j__strlen(Str);
  if ( len >= 24 )
  {
    sub_40247D(Str, v2, v1);
    sub_40384B(v1);
  }
  printf("you are too short!");
  return 0;
}
from idaapi import *
from idc import *
v15 = 0x90, 0x0F, 0xB6, 0x55, 0xF7, 0x8B, 0x45, 0x08, 0x8B, 0x04,
  0x90, 0x0F, 0xAF, 0x45, 0xFC, 0x33, 0xD2, 0xF7, 0x75, 0xF8,
  0x0F, 0xB6, 0x4D, 0xF7, 0x8B, 0x45, 0x0C, 0x89, 0x14, 0x88]
b = 0xF78824
for i in range(30):
    ida_bytes.patch_byte(b + i, v15[i])
from idaapi import *

[培训]科锐逆向工程师培训第53期2025年7月8日开班!

最后于 2024-6-6 10:26 被Brinmon编辑 ,原因: 忘记传附件了
上传的附件:
收藏
免费 0
支持
分享
最新回复 (2)
雪    币: 3751
活跃值: (2432)
能力值: ( LV3,RANK:25 )
在线值:
发帖
回帖
粉丝
2
有附件么,大佬
2024-6-6 09:46
0
雪    币: 7777
活跃值: (3233)
能力值: ( LV13,RANK:430 )
在线值:
发帖
回帖
粉丝
3
Delevy 有附件么,大佬
这是BUUSCTF上的一道题,第四页,SWPU2019_EasiestRe,忘记传了
2024-6-6 10:22
0
游客
登录 | 注册 方可回帖
返回