一种注入进程,获得完全操控的方法之二

AI权益加码!Claude Code、Cursor等20+工具免费用! 购周边限时加赠Coding Plan Lite,畅享主流AI工具!学习进阶更高效! 阅读详情
作 者: menting
时 间: 2007-12-12,16:50
链 接: http://bbs.pediy.com/showthread.php?t=56442

看到了我的之一,我想大家会很清楚,因为这个方法的最大的BUG就是在回调函数之后来处理,如果前面已经处理了,
那么我们就无法处理了。而且又要修改系统DLL,比较不完美。我最近又发现了两种方法:
  一、修改RegisterClassA:
  相对前面的方法来说,这个方法很好用,因为,我们可以很容易把回掉函数改掉。类似如下代码:
//---------------------------------------------------------------------------
int CMuGame::InitRegClass()
{  
  //获取模块句柄:
  HINSTANCE hModule=::GetModuleHandle("User32.dll");
  //获取原始函数地址:
  fpsRegisterClassA=(REGWINCLASS)::GetProcAddress(hModule,"RegisterClassA");

  //获取当前内存块的保护类型:
  MEMORY_BASIC_INFORMATION _base;
  ::VirtualQuery((LPVOID)((DWORD)hModule+0x1000),&_base,sizeof(MEMORY_BASIC_INFORMATION));

  //处理为读写类型:
  ::VirtualProtect(_base.BaseAddress,_base.RegionSize,PAGE_READWRITE,&_base.Protect);

  //获得导出表的地址和大小:
  DWORD   dwExportSize=NULL;
  PDWORD  pdwExportAddr=NULL;

  appfun.Load(hModule);
  appfun.GetExportTable(&dwExportSize,&pdwExportAddr);

  //查找RegisterClassA函数地址:
  for(DWORD i=0;i<dwExportSize;i++,pdwExportAddr++)
  {
    if((*pdwExportAddr+(DWORD)hModule)==(DWORD)fpsRegisterClassA)
    {
      //计算跳转地址:
      DWORD  dword=(DWORD)fpnRegisterClassA-(DWORD)fpsRegisterClassA;
    
      //声明结构对象:
      _ASM_JMP _jmp;
      _jmp._01cmd =0xE9;
      memcpy((PDWORD)_jmp._02dat,&dword,4);
      memcpy((LPVOID)((DWORD)fpsRegisterClassA-5),&_jmp,5);

      //修改导出表地址:
      DWORD  dwAddr=*pdwExportAddr-5;
      memcpy(pdwExportAddr,&dwAddr,4);

      break;
    }
  }

  //处理完成后,恢复保护类型:
  DWORD dwProctect=NULL;
  ::VirtualProtect(_base.BaseAddress,_base.RegionSize,_base.Protect,&dwProctect);
  return NULL;
}
//----------------------------------------------------------------------------



  当然,我们可以修改IAT表来实现,但是我们大家都明白,IAT表很不确定,有的程序还没有IAT表,我们必须找个通用
的方法,那就是直接把User32.dll的导出表修改掉,因此,我们让程序正常调用RegisterClassA这个之后,千万没想到的是,现
在的导处API函数的地址已经被修改,而在中途转到我们的DLL中,然后再回到真正的函数地址入口:

//-----------------------------------------------------------------------------

ATOM WINAPI fpnRegisterClassA(WNDCLASS *lpWndClass)
{
  //替换"XX"窗口的回调函数:
  if(lstrcmp(lpWndClass->lpszClassName,"XX")==0) //如果是我们要替换的窗口,就替换,不是就不替换
  {
    fpsWndProc=lpWndClass->lpfnWndProc;
    lpWndClass->lpfnWndProc=fpnWndProc;
  }
  ATOM  atom=fpsRegisterClassA(lpWndClass);
  return atom;
}

LRESULT CALLBACK fpnWndProc(HWND hDlg,UINT message,WPARAM wParam,LPARAM lParam)
{
  switch(message)
  {
  case WM_INITDIALOG:
    {
      //保存窗口句柄:
      theApp.game.hWnd=hDlg;
      //修改标题,方便我们调用:
      ::SetWindowText(hDlg,_T("[PhantomNet] XX"));  //我们把标题修改掉,方便通信,可以不修改的。
      break;
    }
  case WM_CMD:   //自定义命令:
    {
      if((DWORD)wParam==0x01){PostQuitMessage(0);} //收到命令,我们直接用API让程序结束。
      if((DWORD)wParam==0x02){}   //……什么操作都可以
      break;
    }
  default:{break;}
  }
  //转到游戏的回调函数:
  return fpsWndProc(hDlg,message,wParam,lParam);
}


//----------------------------------------------------------------------------------------


上面的代码就是实现修改RegisterClassA注册类,来转到我们的回调函数的。我们的回调函数,是在真正的回调函数
之前就被执行的,我们可以截获部分消息,让真正的回调函数收不到,因为,我们事先已经替它处理了事件。这样就避免了部
分消息收不到,但是这样的方法,是在程序没有启动,而随程序启动而加载……,我们就没办法对现有的进程进行操作。


  二、直接替换回调函数:
  怎么能直接替换呢?很多朋友都会想改这个改那个,实际KS给我们4个函数来让我们做这个工作。但是局限在同一进程,
//----------------------------------------------
GetClassLong(HWND hWnd,int Index);
GetWindowLong(HWND hWnd,int Index);
SetClassLong(HWND hWnd,int nIndex,LONG dwNewLong);
SetWindowLong(HWND hWnd,int nIndex,LONG dwNewLong);
//----------------------------------------------
  有必要对这两类函数做说明,GetClassLong和SetClassLong在RegisterClassA这个函数运行时才起作用,而GetWindowLong
和SetWindowLong在CreateWindowA后才有作用。我们完全可以不用CreateRemoteThread这个来触发,我们的程序。我们在替换回调
函数时可以在其他进程对目标进程处理,我们只需要把程序写入到目标进程,我们没必要专门去创建一条线程来加载DLL,我们直接
把它写进去后,再让某个消息来触发加载。那样就会隐蔽点,这里简要说一下,为了安全期间不贴代码了。

//--------------------------------------------------

int CMgMuAssistantApp::LoadMain()
{
  //初始化SOCKET:
  if (!AfxSocketInit())
  {
    AfxMessageBox("Error InitSocket!");
  }
  //查找窗口是否存在:
  pWnd=CWnd::FindWindow(NULL,"XX");
  if(pWnd!=NULL)
  {
    //由于窗口有可能在创建前被找到,所以我们完善期间不用GetWindowLong,
    //保存原始窗口回调函数:
    fpsWndProc=(WNDPROC)::GetClassLong(pWnd->m_hWnd,GCL_WNDPROC);

    //由于SetClassLong只在注册类时起作用,我们必须用SetWindowLong;
    //修改回调函数:
    ::SetWindowLong(pWnd->m_hWnd,GWL_WNDPROC,(LONG)fpnWndProc);  

    //修改Socket函数:
    hooksocket.InitHookApi(::GetModuleHandle(NULL),0x00376000,0x0568);

    //装载OpenGL:
    PDWORD pdwAddr=(PDWORD)((DWORD)::GetModuleHandle(NULL)+0x00375A00);
    *pdwAddr=(DWORD)fpnRender;
    pdwAddr  =(PDWORD)((DWORD)::GetModuleHandle(NULL)+0x002B5E69);
    *pdwAddr=(DWORD)((DWORD)::GetModuleHandle(NULL)+0x00375A00);
  }

  return 0;
}

//---------------------------------------------------
  上面的代码是我针对某个游戏做的,由于游戏是基于OpenGL的,所以我就把OpenGL的Render修改下来,来处理我的代码
比如,我们要用到程序内部函数:

//-----------------------------------------------------------
//原程序是如下的调用方法:
00664B75  |.  50            push    eax
00664B76  |.  8D55 8C       lea     edx, dword ptr [ebp-74]
00664B79  |.  52            push    edx
00664B7A  |.  A1 181E9E07   mov     eax, dword ptr [79E1E18]
00664B7F  |.  83C0 14       add     eax, 14
00664B82  |.  50            push    eax
00664B83  |.  8B0D 141E9E07 mov     ecx, dword ptr [79E1E14]
00664B89  |.  83C1 23       add     ecx, 23
00664B8C  |.  51            push    ecx
00664B8D  |.  E8 8E7CF2FF   call    0058C820

//我把它做成C函数调用,这样我们就可以直接用这个函数来调用程序内部函数了:
int CMgMuAssistantApp::SetMainText(int x,int y,LPSTR str,int unk1,int unk2,int unk3)
{
  ShowText=(MAINTEXT)0x0058C820;
  ShowText(x,y,str,unk1,unk2,unk3);
  return 0;
}

//---------------------------------------------------------------------


下面是我的回调函数,我们发现我们再发送命令给目标程序时,目标程序就乖乖的按我们说的做,让它放那,它就放那,让
它返回什么,它就乖乖返回什么,我们可以设置更多的命令来对程序操作:
//--------------------------------------------------------------------
LRESULT CALLBACK fpnWndProc(HWND hDlg,UINT message,WPARAM wParam,LPARAM lParam)
{
  //保存窗口句柄:
  theApp.game.hWnd=hDlg;

  switch(message)
  {
  case WM_INITDIALOG:{break;}
  case WM_PAINT:{break;}
  case WM_CMD:
    {
      if((DWORD)wParam==0x01){PostQuitMessage(0);}
      //返回的是主程序句柄:
      if((DWORD)wParam==0x02){
        //保存主程序句柄:
        theApp.m_hWndMainApp=(HWND)lParam;
        //返回游戏句柄:
        ::SendMessage(theApp.m_hWndMainApp,WM_CMD,0x02,(LPARAM)hDlg);
      }
      if((DWORD)wParam==0x08){
        //连接主程序,这里我创建了SOCKET来网络传输数据:
        theApp.m_uPortMainApp=(UINT)lParam;
        pClient=new CClient;
        pClient->Close();
        pClient->Create();
        if(lstrcmp(theApp.m_strAddrMainApp,"")==0)
        {
          //获取主机地址:
          char hostname[MAX_PATH]={0};
          ::gethostname(hostname,MAX_PATH);
          hostent *addr=::gethostbyname(hostname);
          theApp.m_strAddrMainApp=inet_ntoa(*(struct in_addr *)addr->h_addr_list[0]);
        }
        if(pClient->Connect(theApp.m_strAddrMainApp,theApp.m_uPortMainApp)==FALSE)
        {
          ::SendMessage(theApp.m_hWndMainApp,WM_CMD,0x08,(LPARAM)-1);
        }else{::SendMessage(theApp.m_hWndMainApp,WM_CMD,0x08,(LPARAM)1);}
      }
      if((DWORD)wParam==0x10){    
        //修改标题,方便我们调用:
        ::SetWindowText(hDlg,_T("[MG] MU"));
      }
      if((DWORD)wParam==0x11){
        CRect rect;
        //获取窗口矩形:
        ::GetWindowRect(hDlg,&rect);
        //移动窗口:
        ::MoveWindow(hDlg,LOWORD(lParam),HIWORD(lParam),rect.Width(),rect.Height(),TRUE);
      }
      return TRUE; //直接返回,不让游戏回调处理,这个是我们的命令机密不能让程序知道:
    }
  case WM_COPYDATA:  //我们替我们的目标程序处理进程间通信消息,为了方便点:)
    {
      //wParam:窗口句柄
      //lParam:数据
      theApp.OnCopyData(CWnd::FromHandle((HWND)wParam),(COPYDATASTRUCT*)lParam); return TRUE;
    }
  default:{break;}
  }
  //转到游戏的回调函数:
  return fpsWndProc(hDlg,message,wParam,lParam);
}

//-----------------------------------------------------------------------------------------------

  实际这回是在上回的基础而来的,我们总结一下就知道,当我们完全操作了回调函数时,一个应用程序就几乎成了你
手中的蛋糕,想怎么样吃就怎么样吃:).KS在进程的通信和相互性上没做多少,我们很多时候都要用CreateRemoteThread这个
函数来做DLL的加载,实际不用它的方法还是有很多的,只是没有被人发现而已,同过前面的说明,我想大家都会明白了,怎么
样把一个程序完全操控,但是回过头来一想,如果我们对一个进程做了完全操作,我们可以再用这个进程操作其它的进程,那么
会是烦琐点,但是是件很让人恐怖的事。前面的这个回调函数处理的事情很少,因为,我没把它做的有多强,我不想把它做多强
实际,当一个进程的回调函数交给你来处理,那么我们就可以做很多我们想做的事。当我们将DLL放入某个进程时,我们就可以
调用它的任意一个函数,来为我们工作,我们只需要做影射,把我们要调用的函数和地址影射到我们的DLL中,然后再加工~~~~


:)^^^^
 
DLL注入实战:3招轻松攻破进程 本文提供了Windows环境下DLL注入的实战指南,包含三种可直接上手的实现方案。通过远程线程注入(最通用)、进程创建时注入和注册表注入三种方式,详细介绍了操作步骤和完整代码实现。重点阐述了DLL加载原理、权限要求等前置知识,并给出位数一致性、权限问题等关键注意事项。文章还推荐了ProcessExplorer等辅助工具,帮助验证注入效果。特别强调实际应用中需遵守法律法规,建议从远程线程注入方案开始练习。所有方案都经过实践验证,确保新手也能快速掌握这项技术。 阅读详情

相关推荐

SetWindowLong和SetClassLongh函数关于索引GWL_WNDPROC,GCL_WNDPROC的区别

个人看法,如有雷同,纯属巧合!!!SetWindowLong:The SetWindowLong function changes an attribute of the specified window. The function also sets the 32-bit (long) value at the specified offset into the extra window m

coolmousewife的专栏 5814

Win32 API 列表5 (格式有点乱)

西安邮电学院 徐兆元1201 SetBoundsRect 控制相邻矩形重叠  Yes Yes Yes1202 SetBrushOrgEx 设置当前刷子的起点  No Yes Yes1203 SetCapture 设置鼠标捕获 "    函数功能:该函数在属于当前线程的指定窗口里设置鼠标捕获。一旦窗口捕获了鼠标,所有鼠标输入都针对该窗口,无论光标是否在窗口的边界内。同一时刻只能有一个窗口捕获鼠标

FLxyzsby的专栏 1万+

SetClassLong

SetClassLong   函数功能:该函数替换在额外类存储空间的指定偏移地址的32位长整型值,或替换指定窗口所属类的WNDCLASSEX结构。  函数原型:DWORD SetClassLong(HWND hWnd,int nlndex,LONG dwNewLong);  参数:  hWnd:窗口句柄及间接给出的窗口所属的类。  nlndex:指定

laurensky的专栏 1411

C++的回调函数

回调函数主要在“回”字,和正常的函数调用方式不太一样。正常的函数由开发者自己定义返回类型以及传入的参数,并且也是由开发者自己调用,而回调函数功能其实也是由开发者自己实现,但是返回类型以及入参则由注册回调的函数来决定(若是自己编写则可以自定义注册函数,由他人提供则只能根据接口实现),而且调用方也不是开发者,而是注册方决定。整个过程也就是一个“回”字,开发者将自己的函数指针交给对方,这是“去”,而对方则在适当的时候调用这个函数,也可以将一些开发者需要的数据传回来,这便是来回了。

QtCompany的博客 572

WIN钩子注入

在Windows系统下,每个进程都拥有独立的资源空间,采用的是虚拟地址。 简单来说,即使你知道另一个进程的某个变量的内存地址,你却没办法使用别的进程来直接访问的。 哪怕这个地址的是通过 malloc() 等分配的动态内存也不行的。 一般而言,我们通过给指定进程注入我们指定的动态库,使其在同一个进程中,然后在通过指定地址访问到某个变量,读取或修改其值。 通常这样的注入的方式有两种: 1.由指定进程...

BCMY0110的博客 400

一种注入进程获得完全操控方法

作 者: menting好长时间没贴东西了,今天就来贴点东西,废话就不说了直接进入主题,喜欢的就支持,不喜欢的就看乐和!!  今天说点什么呢~我们今天就说HOOK,实际提到这个大家都知道它的功用,如果要是抓取消息那肯定是用下面的函数://----------------------------------------------------------------------::SetWindow

1380

一种注入进程获得完全操控方法之一

链 接: http://bbs.pediy.com/showthread.php?t=56036 好长时间没贴东西了,今天就来贴点东西,废话就不说了直接进入主题,喜欢的就支持,不喜欢的就看乐和!!  今天说点什么呢~我们今天就说HOOK,实际提到这个大家都知道它的功用,如果要是抓取消息那肯定是用下面的函数: //-----------------------------

Dantin的专栏 3448

一种注入进程获得完全操控方法之一[先贴过来,等下研究一下,看起来不错]

引用自:http://bbs.pediy.com/showthread.php?t=56036标 题: 【原创】一种注入进程获得完全操控方法之一作 者: menting时 间: 2007-12-05,17:26链 接: http://bbs.pediy.com/showthread.php?t=56036好长时间没贴东西了,今天就来贴点东西,废话就不说了直接进入主题,喜欢的就支持,不喜欢的

AlbertLi 1706

修改任意Linux进程地址空间实施代码注入

提到进程注入,常规的方案就是使用ptrace,其POKEDATA,POKETEXT命令选项单从名字上就知道是干什么的,这里不再赘述。 然而ptrace是个系统化的东西,太复杂,不适合玩手艺,有没有什么适合手工玩的东西呢?当然有! 正如读写/dev/mem可以手工完成crash+gdb的功能hack内核一样,每一个用户态进程也有一个mem文件,即 /proc/$pid/mem 。 我不敢保证每一个系统该文件都可写,但一旦它可写就好玩了。 /proc/$pid/mem文件抽象的一个进程的地址空间,直接写该文

TCP/IP 6886

Xenos注入器深度解析:Windows进程操控DLL注入技术实战指南

Xenos是一款基于Blackbone库开发的专业级Windows DLL注入器,专为技术开发者和安全研究人员设计。这款工具在Windows进程注入、动态链接库操控和系统调试领域提供了完整的技术解决方案。无论是进行软件逆向分析、系统安全测试还是进程功能扩展,Xenos都能提供强大的进程操控能力。 ## 🔧 技术背景与项目定位 在Windows系统开发和安全研究领域,进程注入技术是核心技术之一

gitblog_00951的博客 187

掌握Windows进程操控艺术:Xenos注入器深度解析

Xenos是一款基于Blackbone库开发的Windows DLL注入器,专为需要在Windows系统中进行进程操控的开发者和技术爱好者设计。这款工具能够帮助用户将动态链接库(DLL注入到指定进程中,实现进程增强、功能扩展或调试分析等高级操作。 ## 🚀 核心功能解析 ### DLL注入核心机制 Xenos的核心功能实现位于[InjectionCore.h](https://link.g

gitblog_00004的博客 394

如何使用Xenos:Windows DLL注入终极指南,让进程操控变得简单高效

Xenos是一款基于Blackbone库开发的强大Windows DLL注入工具,专为开发者和安全研究人员设计。它在Windows平台上展现出卓越的灵活性和多功能性,支持x86和x64架构的进程与模块注入,以及内核模式注入等多种注入方式,是进行软件调试、性能分析、恶意代码研究和系统级插件开发的理想选择。 ## 项目介绍:探索Xenos的核心功能 Xenos作为一款专业的Windows DLL注...

gitblog_00925的博客 425

Windows进程内存操控的艺术:Xenos DLL注入器深度解析

当我们面对Windows系统下需要深度监控、调试或扩展第三方应用程序功能时,常常会遇到一个技术瓶颈:如何在不修改原始程序的情况下,将自定义代码注入到目标进程的内存空间中运行?这正是DLL注入技术要解决的核心问题。今天,我们将深入探讨一个基于Blackbone库构建的专业级Windows DLL注入器——Xenos,看看它如何将这一复杂技术变得简单高效。 ## 为什么我们需要专业的DLL注入工具?

gitblog_00039的博客 470

Windows进程内存操控的终极指南:Xenos DLL注入器完整解析

你是否曾想过在不修改源代码的情况下,为Windows应用程序添加新功能?或者需要深度监控第三方软件的内部运行状态?这正是**DLL注入技术**和**Windows进程内存操控**的魅力所在。今天,我们将深入探索Xenos——一个基于Blackbone库构建的专业级**DLL注入工具**,揭秘它如何将复杂的进程操控技术变得简单高效。 ## 🎯 功能亮点:为什么Xenos是开发者的秘密武器? 想

gitblog_00698的博客 429

多种DLL注入技术原理介绍

本文中我将介绍DLL注入的相关知识。不算太糟的是,DLL注入技术可以被正常软件用来添加/扩展其他程序,调试或逆向工程的功能性;该技术也常被恶意软件以多种方式利用。这意味着从安全角度来说,了解DLL注入的工作原理是十分必要的。 不久前在为攻击方测试(目的是为了模拟不同类型的攻击行为)开发定制工具的时候,我编写了这个名为“injectAllTheThings”的小工程的大...

顺其自然~专栏 3万+
上一篇: PE文件格式的RVA概念
下一篇: shellcode之小小琢磨
iiprogram
博客等级 码龄25年 1066粉丝 1515原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值