zoukankan      html  css  js  c++  java
  • 利用DEBUG API编写Loader Path

        Loader并不是什么很神秘的技术,微软提供了一组Debug Api来方便第三方监视程序.这里我用Debug Api制作了一个简单的Loader程序.
       这个Loader要干的事有:
       1.启动目标程序.
       2.读取/修改目标程序的内存 或 寄存器
       用到的Debug Api有:
      CreateProcess —— 用于创建被调试进程
      WaitForDebugEvent —— Debug Loop(调试循环)的主要构成函数
      ContinueDebugEvent —— 用于构成Debug Loop
      GetThreadContext —— 得到被调试进程的寄存器信息
      SetThreadContext —— 设置被调试进程的寄存器信息
      ReadProcessMemory —— 得到被调试进程的内存内容
      WriteProcessMemory —— 设置被调试进程的内存内容

       相应的数据结构如下
      CONTEXT —— 寄存器结构
      STARTUPINFO —— Start信息
      PROCESS_INFORMATION —— 进程相关信息
      DEBUG_EVENT —— Debug Event(调试事件)结构
       Loader具体代码如下:
    // MemoryReader.cpp : 定义控制台应用程序的入口点。
    // AntiDebug:IsDebugPresent如何避开?
    // 加壳处理不完善
    //

    #include 
    "stdafx.h"
    #include 
    "windows.h"
    #include 
    "Commdlg.h"
    #include 
    "winnt.h"

    BYTE INT3 
    = 0xCC;

    //写入前的
    BYTE Old;

    //页面属性
    DWORD OldProtect;

    //是否已写入INT3
    bool HasINT3 = false;

    bool IsFirstINT3 = true;

    DWORD BreakPoint 
    = 0x00452191;

    BYTE Org[
    8= {0xE8,0x4E};

    //判断是否解压完成
    bool IsUnpacked(PROCESS_INFORMATION pi)
    {
        SuspendThread(pi.hThread);
        CONTEXT context;
        ZeroMemory(
    &context,sizeof(CONTEXT));
        context.ContextFlags 
    = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS;
        GetThreadContext(pi.hThread,
    &context);
        printf(
    "Exe Info:Eax:%x,Esp:%x,Eip:%x\n",context.Eax,context.Esp,context.Eip);        
        ResumeThread(pi.hThread);
        BYTE mem[
    8];
        VirtualProtectEx(pi.hProcess,(LPVOID)BreakPoint,
    1,PAGE_READWRITE, &OldProtect);
        ReadProcessMemory(pi.hProcess,(LPCVOID)BreakPoint,
    &mem,8,NULL);
        VirtualProtectEx(pi.hProcess,(LPVOID)BreakPoint,
    1,OldProtect,&OldProtect);
        printf(
    "hex num is:%x,%x,%x,%x\n",mem[0],mem[1],mem[2],mem[3]);
        
    if(mem[0^ 0xff == Org[0&& mem[1^ 0xff == Org[1])
        {
            
    //不能乱调用
            Old = mem[0];
            
    return TRUE;
        }
        
    return false;
    }

    //写INT3
    bool WriteINT3(PROCESS_INFORMATION pi)
    {
        
    //VirtualAllocEx(pi.hProcess,(LPVOID)0x0101259b,sizeof(INT3), MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
        SuspendThread(pi.hThread);
        VirtualProtectEx(pi.hProcess,(LPVOID)BreakPoint,
    1,PAGE_READWRITE, &OldProtect);
        
    bool ret = WriteProcessMemory(pi.hProcess,(LPVOID)BreakPoint,&INT3,sizeof(INT3),NULL);
        VirtualProtectEx(pi.hProcess,(LPVOID)BreakPoint,
    1,OldProtect,&OldProtect);
        HasINT3 
    = ret;
        ResumeThread(pi.hThread);
        
    return ret;
    }

    //改回去
    bool CleanINT3(PROCESS_INFORMATION pi)
    {
        
    //SuspendThread(pi.hThread);
        bool ret = WriteProcessMemory(pi.hProcess,(LPVOID)BreakPoint,&Old,sizeof(Old),NULL);
        
    if(ret == false)
        {
            printf(
    "改回去失败!\n");
        }
        CONTEXT context;
        ZeroMemory(
    &context,sizeof(CONTEXT));
        context.ContextFlags 
    = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS;
        GetThreadContext(pi.hThread,
    &context);
        context.Eip
    --;
        SetThreadContext(pi.hThread,
    &context);

        printf(
    "已经改回去了,Eax:%x\n",context.Eax);
        
    return ret;
    }

    //隐藏Debug
    void HideDebug(PROCESS_INFORMATION pi)
    {
        BYTE ISDEBUGFLAG 
    = 0x00;
        
    int ISHEAPFLAG = 2;
        SuspendThread(pi.hThread);
        CONTEXT context;
        ZeroMemory(
    &context,sizeof(CONTEXT));
        context.ContextFlags 
    = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS;
        GetThreadContext(pi.hThread,
    &context);
        
    //IsDebugPresent_Flag
        WriteProcessMemory(pi.hProcess,(LPVOID)(context.Ebx+0x2),&ISDEBUGFLAG,1,NULL);
        
    //NTGlobal_Flag  用0D则为70  这个为0 防止其他调试器存在
        WriteProcessMemory(pi.hProcess,(LPVOID)(context.Ebx+0x68),&ISDEBUGFLAG,1,NULL);
        
    //GetProcessHeap_Flag
        DWORD HeapAddress;
        ReadProcessMemory(pi.hProcess,(LPCVOID)(context.Ebx 
    + 0x18),&HeapAddress,sizeof(HeapAddress),NULL);
        WriteProcessMemory(pi.hProcess,(LPVOID)HeapAddress,
    &ISHEAPFLAG,sizeof(ISHEAPFLAG),NULL);

        ReadProcessMemory(pi.hProcess,(LPCVOID)(context.Ebx 
    + 0x68),&ISDEBUGFLAG,1,NULL);
        printf(
    "NT_GLOBAL=%d\n",ISDEBUGFLAG);
        ResumeThread(pi.hThread);
    }


    int main(int argc, char* argv[])
    {
        
    char f_name[256];
        f_name[
    0= NULL;
        OPENFILENAME filename;
        ZeroMemory(
    &filename,sizeof(OPENFILENAME));
        filename.lStructSize 
    = sizeof(OPENFILENAME);
        filename.hwndOwner 
    = NULL;
        filename.lpstrFilter 
    = "*.exe";
        filename.lpstrFile 
    = f_name;
        filename.nMaxFile 
    = 256;
        filename.lpstrInitialDir 
    = NULL;
        filename.Flags 
    = OFN_EXPLORER | OFN_HIDEREADONLY;
        
    if(!GetOpenFileName(&filename))
            
    return 0;
        STARTUPINFO si;
        PROCESS_INFORMATION pi;
        ZeroMemory(
    &si,sizeof(STARTUPINFO));
        ZeroMemory(
    &pi,sizeof(PROCESS_INFORMATION));
        
    bool ret = CreateProcess(filename.lpstrFile,"",NULL,NULL,FALSE,DEBUG_PROCESS,NULL,NULL,&si,&pi);
        
    if(ret == false)
        {
            MessageBox(NULL,
    "创建进程失败!","",0);
            
    return -1;
        }

        
    //Anti-Anti-Debug
        HideDebug(pi);

        DEBUG_EVENT devent;
        
    int DllCount = 0;
        
    while(TRUE)
        {
            
    if(WaitForDebugEvent(&devent,1))
            {
                
    switch(devent.dwDebugEventCode)
                {
                
    case CREATE_PROCESS_DEBUG_EVENT:
                    printf(
    "CREATE_PROCESS_DEBUG_EVENT\n");
                    
    break;
                
    case CREATE_THREAD_DEBUG_EVENT:
                    printf(
    "CREATE_THREAD_DEBUG_EVENT\n");
                    
    break;
                
    case EXCEPTION_DEBUG_EVENT:
                    
    //printf("EXCEPTION_DEBUG_EVENT\n");
                     switch(devent.u.Exception.ExceptionRecord.ExceptionCode)
                    {
                    
    case EXCEPTION_BREAKPOINT:
                        
    if(HasINT3)
                        {    
                            SuspendThread(pi.hThread);
                            CONTEXT context;
                            ZeroMemory(
    &context,sizeof(CONTEXT));
                            context.ContextFlags 
    = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS;
                            GetThreadContext(pi.hThread,
    &context);
                            printf(
    "Eax:%x\n,Esi:%x\n,Eip:%x\n,Ebp:%x\n",context.Eax,context.Esi,context.Eip,context.Ebp); 
                            
    if(context.Eip == BreakPoint + 1)
                            {
                                
    if(!CleanINT3(pi))
                                {
                                    printf(
    "清除断点失败!");
                                }

                                printf(
    "Program Stopped At What We Want\n");
                                
    char key[256];

                                VirtualProtectEx(pi.hProcess,(LPVOID)BreakPoint,
    1,PAGE_READWRITE, &OldProtect);
                                ReadProcessMemory(pi.hProcess,(LPCVOID)context.Edx,key,
    sizeof(key),NULL);
                                VirtualProtectEx(pi.hProcess,(LPVOID)BreakPoint,
    1,OldProtect,&OldProtect);
                                
                                printf(
    "读出来的东西是 %s\n",key);        
                            }
                            ResumeThread(pi.hThread);
                        }    
                        
    break;
                    
    case EXCEPTION_SINGLE_STEP:
                        printf(
    "2 EXCEPTION_SINGLE_STEP\n");
                        
    break;
                    
    case EXCEPTION_ACCESS_VIOLATION:
                        printf(
    "读写地址出错\n");
                        printf(
    "%d,%x\n",devent.u.Exception.ExceptionRecord.ExceptionInformation[0],devent.u.Exception.ExceptionRecord.ExceptionAddress);

                        ContinueDebugEvent(pi.dwProcessId,pi.dwThreadId,DBG_EXCEPTION_NOT_HANDLED);

    /*                    char Nop[3];
                        Nop[0] = 0x90;
                        Nop[1] = 0x90;
                        Nop[2] = 0x90;
                        PVOID pathAddress;
                        pathAddress = devent.u.Exception.ExceptionRecord.ExceptionAddress;
                        VirtualProtectEx(pi.hProcess,pathAddress,3,PAGE_READWRITE, &OldProtect);
                        WriteProcessMemory(pi.hProcess,pathAddress,Nop,3,NULL);
                        VirtualProtectEx(pi.hProcess,(LPVOID)BreakPoint,1,OldProtect,&OldProtect);

                        ContinueDebugEvent(pi.dwProcessId,pi.dwThreadId,DBG_EXCEPTION_NOT_HANDLED);        
    */        
                        
    break;
                    
    default:
                        
    break;
                    }
                    
    break;
                
    case LOAD_DLL_DEBUG_EVENT:
                    
    //获取DLL NAME太复杂,暂时做不到
                    DllCount ++;
                    printf(
    "%d,Program Loads a Dll From BaseImage:%x,ImageName:%x\n",DllCount,devent.u.LoadDll.lpBaseOfDll,devent.u.LoadDll.lpImageName);                
                    
    if(!HasINT3)
                    {
                      
    if(IsUnpacked(pi))
                      {
                          printf(
    "UnPacked Success!!\n");
                          WriteINT3(pi);
                          printf(
    "Write a INT3\n");
                      }
                    }
                    
    break;
                
    case UNLOAD_DLL_DEBUG_EVENT:
                    printf(
    "UnLoad a Dll From BaseImage:%x,ImageName:%x\n",devent.u.LoadDll.lpBaseOfDll,devent.u.LoadDll.lpImageName);                
                    
    if(!HasINT3)
                    {
                      
    if(IsUnpacked(pi))
                      {
                          printf(
    "UnPacked Success!!\n");
                          WriteINT3(pi);
                          printf(
    "Write a INT3\n");
                      }
                    }
                    
    break;
                
    case OUTPUT_DEBUG_STRING_EVENT:
                    
    break;
                
    case EXIT_PROCESS_DEBUG_EVENT:
                    printf(
    "调试程序已退出");
                    
    break;
                
    default:
                    printf(
    "%d\n",devent.dwDebugEventCode);
                    
    break;
                }
                ContinueDebugEvent(pi.dwProcessId,pi.dwThreadId,DBG_CONTINUE);
            }
            
    else
            {
            }
        }
        
    //KeyMake中不要这两句
        CloseHandle(pi.hProcess);
        CloseHandle(pi.hThread);
        
    return 0;
    }


           目前版本功能:
          1.启动目标程序
          2.向指定位置写入INT3断点
          3.读取/设置指定位置寄存器值
          4.读取/修改指定位置内存值
          5.解压一些压缩和加密壳
          6.一些Anti-Anti-Debug功能

  • 相关阅读:
    [导入]在.NET下如何实现密码Hash化
    [导入]强大的.NET反编译工具Reflector及插件
    [导入]XML数据岛(XML Data Island)
    验证视图状态 MAC 失败。处理办法
    ASP.NET格式化字符串
    .NET 开发框架技术资料搜集
    网页中图片大小自动调整三种方法
    用户 'azhk' 登录失败。原因: 未与信任 SQL Server 连接相关联。
    jstl及el表达式笔记
    杰普Core Java课程笔记1
  • 原文地址:https://www.cnblogs.com/Red_angelX/p/738552.html
Copyright © 2011-2022 走看看