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功能

  • 相关阅读:
    &&和||解析
    SQL-union union all
    sql杂记
    JAVA杂记
    sql之left join、right join、inner join的区别
    蓝鲸邮箱配置
    快速部署社区版(详解)
    蓝鲸平台安装环境准备
    蓝鲸脚本集合
    zabbix3.4 install
  • 原文地址:https://www.cnblogs.com/Red_angelX/p/738552.html
Copyright © 2011-2022 走看看