逆向分析初体验

  1. 所逆向程序没有加壳
  2. 程序进行加壳
  3. 程序有CRC检测,我们需要使用VEH来跳过检测
  4. 总结

ps:时间原因,我已经找到程序关键跳地址为0X004010FD,该地址指令长度为6

所逆向程序没有加壳

  • 因为程序没有加壳,我们可以直接选择使用修改二进制文件0X004010FD处指令为{\x90,\x90,\x90,\x90,\x90,\x90}

  • 但是我选择写C语言程序进行内存写入修改,代码如下

    #define _CTR_SECURE_NO_WARNINGS
    #include<stdio.h>
    #include<string.h>
    #include<stdlib.h>
    #include<windows.h>
    int main1(){
        DWORD a;
        //输如PID
        scanf_s("%d", &a);
        byte buf[] = { 0x90,0x90 ,0x90 ,0x90 ,0x90 ,0x90 };
        //获取函数句柄
        HANDLE hdle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, a);
        //向指定内存地址写入修改指令
        WriteProcessMemory(hdle, (LPVOID)0x004010FD, buf, 6, NULL);
        printf("破解成功\n");
        system("pause");
        return 0;
    }
  • 执行结果

    输入进程pid

    注册成功截图

程序进行加壳

  • 我们依然可以使用以上方法进行破解,但是在此我使用dll劫持进行演示

  • 首先我们需要使用vs创建dll项目,因为我已经查看到该程序在执行时调用winspool.drv,因此我就准备劫持该dll,关键点在于我们需要将其函数进行转发。

  • 新建项目

    名称需要winspool

  • 在编写dll时注意如下几个问题

    1. 不使用预编译头

    2. 使用字节集编码

    3. 判断程序是不是WOW64程序,代码如下

      BOOL IsWow64Pro = false;
      if (IsWow64Process((HANDLE)-1, &IsWow64Pro)) {
          if (IsWow64Pro)
          {
              GetSystemWow64DirectoryA(tzPath, MAX_PATH);
          }
          else {
              GetSystemDirectory(tzPath, MAX_PATH);
          }
      }
  • 然后在dllmain函数中添加程序代码

    • 如第二种讲的一样直接修改代码

      HANDLE  hadl = OpenProcess(PROCESS_ALL_ACCESS, true,GetProcessId((HANDLE)-1));
      byte buf[] = { 0x90,0x90 ,0x90 ,0x90 ,0x90 ,0x90 };
      WriteProcessMemory(hadl, (LPVOID)0x004010FD, buf, 6, NULL);
      MessageBoxA(NULL, "成功", "标题", NULL);
    • 效果

      注册成功截图2

    • 但是以上的代码存在一些不可预知的效果,比如程序代码还没有还原,则以上代码是无效的,因此考虑增加判断语句,创建新的线程进行判断

    • 线程代码如下

      CreateThread(NULL,NULL, threadPro, NULL, NULL, NULL);
      //线程实现函数,循环检测代码是否被还原
      DWORD WINAPI threadPro(_In_ LPVOID lpParam)
      {
          while (true)
          {
              byte buf = 0 ;
              ReadProcessMemory((HANDLE)-1, (LPVOID)0x004010A9, &buf, 1, NULL);
              //MessageBoxA(NULL, (LPCSTR)buf,"标题" ,NULL );
              if (buf == 0x55) {
                  byte buf2[] = { 0x90,0x90 ,0x90 ,0x90 ,0x90 ,0x90 };
                  WriteProcessMemory((HANDLE)-1, (LPVOID)0x004010FD, buf2, 6, NULL);
                  break;
              }
          }
          return 0;
      }
    • 执行效果

      执行效果

程序有CRC检测,我们需要使用VEH来跳过检测

  • VEH就是异常,让系统捕获相关的异常,然后我们修改上下文

  • 异常捕获代码

    //异常捕获
    DWORD NTAPI ExceptionHandler(EXCEPTION_POINTERS* ExceptionInfo) {
        if ((DWORD)ExceptionInfo->ExceptionRecord->ExceptionAddress == 0x004010FD) {
            ExceptionInfo->ContextRecord->Eip += 6;
            //已经处理异常,不需要再调用下一个异常来处理此异常
            return EXCEPTION_CONTINUE_EXECUTION;
        }
        //调用下一个处理器
        return EXCEPTION_CONTINUE_SEARCH;
    }
  • 注册一个VEH异常

    //注册一个异常VEH
    AddVectoredExceptionHandler(1,(PVECTORED_EXCEPTION_HANDLER)ExceptionHandler);
  • 设置硬件断点

    //设置硬件断点
    void SetHwBreakPoint(HANDLE hThread) {
        CONTEXT ctx;
        ctx.ContextFlags = CONTEXT_ALL;
        GetThreadContext(hThread, &ctx);
        ctx.Dr0 = 0x004010FD;
        ctx.Dr7 = 0x1;
        SetThreadContext(hThread, &ctx);
    }
  • 在win7系统中,此时程序已经被破解掉,但是在win10中发现并没有按照预期进行执行,为什么呢?查询官方解释

    Remarks
    The function sets the thread context based on the value of the ContextFlags member of the context structure. The thread identified by the hThread parameter is typically being debugged, but the function can also operate even when the thread is not being debugged.
    
    Do not try to set the context for a running thread; the results are unpredictable. Use the SuspendThread function to suspend the thread before calling SetThreadContext.
  • 写的很清楚,如果需要设置断点,需要将程序进行挂起

  • 继续更改代码

  • 我们新建一个线程,让新的子线程来接管主线程,到达暂停主线程的目的,防止程序直接假死

    • 创建线程

      CreateThread(NULL,NULL, threadPro, (LPVOID)GetCurrentThreadId(), NULL, NULL);
    • 线程函数

      DWORD WINAPI threadPro(_In_ LPVOID lpParam)
      {
          //打开主线程
          HANDLE hadl = OpenThread(THREAD_ALL_ACCESS, true, (DWORD)lpParam);
          SuspendThread((HANDLE)hadl);
          SetHwBreakPoint(hadl);
          ResumeThread((HANDLE)hadl);
          return 0;
      }
    • 执行结果

      捕获到异常

      执行结果

总结

在程序逆向的过程中,使用dll劫持、HOOK等技术,在有壳的情况小也能方便的达到我们的目的,本文教大家如何手工编写代码并进行调试,谢谢大家阅读。


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 787772394@qq.com

文章标题:逆向分析初体验

本文作者:二豆子·pwnd0u

发布时间:2020-03-13, 13:28:37

最后更新:2023-05-18, 09:30:54

原始链接:http://blog.codefat.cn/2020/03/13/%E9%80%86%E5%90%91%E5%88%9D%E4%BD%93%E9%AA%8C/

版权声明: "署名-非商用-相同方式共享 4.0" 转载请保留原文链接及作者。

目录
×

喜欢就点赞,疼爱就打赏

/*爱心代码*/ /*雪花效果*/ /*百度代码自动提交*/