首页
社区
课程
招聘
[旧帖] [求助]如何用C++把一段汇编写入另一个程序指定的地址或者是修改运行中程序的指令 0.00雪花
发表于: 2011-4-1 09:44 2742

[旧帖] [求助]如何用C++把一段汇编写入另一个程序指定的地址或者是修改运行中程序的指令 0.00雪花

2011-4-1 09:44
2742
我想问一下,我如何修改,原来程序的指令,我这样写有什么不对???
void  CallSelectMonster (long MonsterSn)
{
        _asm{
            mov eax,eax
            mov eax,eax
        }
}

const PCHAR gameCaption="ADD";
void CCALLDlg::OnBnClickedButton1()
{
        int n=1024*50;
        DWORD lpNumberOfBytes;
        LPVOID mFunc=CallSelectMonster;
        HWND gameh=::FindWindow(NULL,gameCaption);//获取窗口句柄

        DWORD processid;
        ::GetWindowThreadProcessId(gameh,&processid);//获取窗口进程ID

        HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS,FALSE,processid);//打开被注入的进程
        //0x0041324A 我想把汇编指令写入到程序的0x0041324A 地址去
        LPVOID ThreadAdd = VirtualAllocEx(hProcess,(LPVOID)0x0041324A,n,MEM_COMMIT,PAGE_EXECUTE_READWRITE);
        BOOL BO = WriteProcessMemory(hProcess,ThreadAdd,mFunc,n, &lpNumberOfBytes); //写入函数地址
        VirtualFreeEx(hProcess,ThreadAdd,n,MEM_RELEASE);//进程中释放申请的虚拟内存空间。

        HANDLE hThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)(ThreadAdd), NULL, 0, &lpNumberOfBytes);//创建一个在其它进程地址空间中运行的线程
        WaitForSingleObject(hThread, INFINITE); //等待线程结束
        VirtualFreeEx(hProcess,ThreadAdd,n,MEM_RELEASE); //进程中释放申请的虚拟内存空间

        CloseHandle(hThread);
        CloseHandle(hProcess);
}

可是我这样写运行后总是出错

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

收藏
免费 0
支持
分享
最新回复 (10)
雪    币: 92
活跃值: (13)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
把一下这两条写入0x0041324A
mov eax,eax
mov eax,eax
我这只是做个实验,请把要讨论他是否有意义
2011-4-1 09:46
0
雪    币: 183
活跃值: (1193)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
3
好像错误很多
等人来详解。
2011-4-1 10:14
0
雪    币: 92
活跃值: (13)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
请人指教,谢谢
2011-4-1 19:59
0
雪    币: 1689
活跃值: (379)
能力值: ( LV15,RANK:440 )
在线值:
发帖
回帖
粉丝
5
void CCALLDlg::OnBnClickedButton1()
{
  int n=1024*50;
  DWORD lpNumberOfBytes;
  LPVOID mFunc=CallSelectMonster;
  HWND gameh=::FindWindow(NULL,gameCaption);//获取窗口句柄

  DWORD processid;
  ::GetWindowThreadProcessId(gameh,&processid);//获取窗口进程ID

  HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS,FALSE,processid);//打开被注入的进程
  LPVOID ThreadAdd = VirtualAllocEx(hProcess,(LPVOID)0x0041324A,n,MEM_COMMIT,PAGE_EXECUTE_READWRITE);
//注意:这里ThreadAdd的值一定不是0x0041324,它是所分配内存区域基址(当指定址址处内存已被提交的话,该值是按页边界对齐的一个值,否则该值是按64k对齐的一个值)。
  BOOL BO = WriteProcessMemory(hProcess,ThreadAdd,mFunc,n, &lpNumberOfBytes); //l因为上边的原因,此处用ThreadAdd作为写入地址明显有问题。
  VirtualFreeEx(hProcess,ThreadAdd,n,MEM_RELEASE);//刚定入了代码还没执行,为什么这么早就把内存释放了?

  HANDLE hThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)(ThreadAdd), NULL, 0, &lpNumberOfBytes);//还是ThradAdd的问题
  WaitForSingleObject(hThread, INFINITE); //等待线程结束
  VirtualFreeEx(hProcess,ThreadAdd,n,MEM_RELEASE); //如果是用MEM_RELEASE标致,那么第三个参数必须为0,否则执行失败。还有第二个参数必须是最初由VirtualAllocEx返回的值,而此时你指定的地址无法确认之前目标进程是否已经提交物理内存。

  CloseHandle(hThread);
  CloseHandle(hProcess);
}

1,建议在调试程序过程中,加上函数返回值的验证代码,这样可以容易确定问题究竟出在了哪里。
2,还有那个地址0x0041324,这是个低端地址,如果已经被系统占用(比如堆),那么对其写入数据可能对目标程序造成破坏。
3,注意VirtualAlloc等内存管理函数地址边界对齐的问题。
4,像这样的地址应该不能随便选吧,感觉。你并不知道系统是否已经用了这个地址。如果你想对目标程序打补丁,那么这个指定的地址就是已经被目标程序用了的,你要做的是向目标地址写入数据(首先得改变页面属性,否则可能写入失败,因为代码段一般没有可写属性)如果你想在目标进程里开辟新的内存空间,那么调用VirtualAlloc一类的内存管理函数才是有意义的。
5,多看下文档,这些内存管理函数有不少细节需要注意,否则很容易出问题。
2011-4-1 20:37
0
雪    币: 692
活跃值: (40)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
6
楼主的代码的问题很多, 我是第一次在看雪发帖,说说我的看法,如有错误,请指正。谢之。

首先,看这个函数:
LPVOID ThreadAdd = VirtualAllocEx(hProcess,(LPVOID)0x0041324A,n,MEM_COMMIT,PAGE_EXECUTE_READWRITE);

第一,你的 内存地址是硬编码为0x0041324A,而在进程空间内,这段内存的状态未知,是保留状态还是已提交状态,不能确定,而msdn上对这个函数的allocationtype参数解释时明确说明:
The function fails if you attempt to commit a page that has not been reserved. The resulting error code is ERROR_INVALID_ADDRESS.

假如这个内存地址的没被保留的话,你直接MEM_COMMIT会导致函数失败。给这个参数建议传递MEM_COMMIT | MEM_RESERVE 并且检查返回值。  或者给内存地址传递NULL值,那么系统将在该进程空间内自动寻找一块你所要求的大小的内存。并将其属性修改。

第二,逻辑混乱,你在将数据写入进程空间后,为什么要接着来个virtualfreeex函数,首先这个函数会执行失败,再者,就算该函数执行成功了,那你后面的线程肯定执行不了任何的代码,因为这句之后该块的内存会变为free状态,线程是没法执行代码的。看看sdk中是怎么说的:

If a page is released, its state changes to free, and it is available for subsequent allocation operations. After memory is released or decommitted, you can never refer to the memory again. Any information that may have been in that memory is gone forever. Attempts to read from or write to a free page results in an access violation exception. If you need to keep information, do not decommit or free memory that contains the information.

在将该块内存release之后,你将决(never)不能再次引用该内存,任何该内存区域的信息都将消失。而且是forever的消失,任何尝试读或者写的操作都将会导致访问违规。
     再来说该函数的参数传递,你在讲MEM_REALSE传递进去后,那个内存块大小的参数必须为0,sdk中说了 是 must be,并且内存地址必须为virtualallocex函数返回的地址。

后面的代码就不多说了,我自己重新写了一遍你的函数,如有错误,望指正。

const PCHAR gameCaption="ADD";

void CallSelectMonster (long MonsterSn)
{
_asm{
mov eax,eax
mov eax,eax
}
} 

BOOL TestFunc()
{
  int iCount = 1024 * 5;
  DWORD dwNumberOfBytes = 0;
  DWORD dwProcessID = 0;
  LPVOID mFunc = CallSelectMonster;
  BOOL fOk = FALSE;
  
  HANDLE hProcess = NULL;
  HANDLE hThread = NULL;
  LPVOID ThreadAddr = NULL;


  __try
  {
	  HWND hGame = ::FindWindowA(NULL, gameCaption);
	  ::GetWindowThreadProcessId(hGame, &dwProcessID);
	  hProcess = ::OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessID);
	  if (hProcess == NULL)
		  __leave;
	  ThreadAddr = ::VirtualAllocEx(hProcess, (LPVOID)0x0041324A, iCount, MEM_COMMIT | MEM_RESERVE,PAGE_EXECUTE_READWRITE);
	  if (ThreadAddr == NULL)
	  {
		  //如果分配失败了,那么由操作系统自己找内存,在来一次
		  ThreadAddr = VirtualAllocEx(hProcess, NULL, iCount, MEM_COMMIT | MEM_RESERVE,PAGE_EXECUTE_READWRITE);
		  if (ThreadAddr == NULL)
		  {
			  printf("error of virtualallocex: %d",::GetLastError());
			  __leave;
		  }
	  }

	  BOOL bWrite = ::WriteProcessMemory(hProcess, ThreadAddr, mFunc, iCount, &dwNumberOfBytes);
	  if (!bWrite)
	  {
		  printf("error of writeprocessmemory: %d",::GetLastError());
		  __leave;
	  }

	  hThread = ::CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)ThreadAddr, NULL, 0, 0);
	  if (hThread == NULL)
	  {
		  printf("error of createremotethread: %d", ::GetLastError());
		  __leave;
	  }

	  ::WaitForSingleObject(hThread, INFINITE);

	  fOk = TRUE;//到了这里,everything is ok...


  }
  __finally
  {
	  if (hProcess != NULL)
	  {
		  if (hThread != NULL)
		  {
			  ::VirtualFreeEx(hProcess, ThreadAddr, 0, MEM_RELEASE);
			  ::CloseHandle(hThread);
		  }

		  ::CloseHandle(hProcess);
	  }



  }

  return fOk;


}
2011-4-2 18:33
0
雪    币: 692
活跃值: (40)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
7
刚才望了说了,我看楼主的代码是在MFC下写的,并且是在主线程里调用了等待函数,赶紧改了吧,要么重启一个线程执行含有waitforsingleobject, 要么就换 MsgWaitForMultipleObjects 否则你的 线程会切入内核状态(堵塞住),窗口无法接受消息,界面假死。
2011-4-2 18:42
0
雪    币: 92
活跃值: (13)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
我看了几位写的,最后我自己有研究了一下,也把代码重新修改了一遍,虽然能运行起,但是还没得到想要的效果,忘各位在指教一下,首先我用OD查看了0x0041324A地址是可以使用的,也是存在的

我修改后的代码:
void CallSelectMonster3 (){
        _asm{
                mov eax,eax
                mov eax,eax
        }
}

void CCALLDlg::OnBnClickedButton3(){
        PCHAR gameCaption3="ADD";
        LPVOID idd3=(LPVOID)0x0041324A;
        int iCount = 1024;

        DWORD dwNumberOfBytes = 0;
        DWORD dwProcessID = 0;
        LPVOID mFunc = CallSelectMonster3;

        HANDLE hProcess = NULL;
        HANDLE hThread = NULL;
        LPVOID ThreadAddr = NULL;
        DWORD dwOldProtect = NULL;

        HWND hGame = ::FindWindowA(NULL, gameCaption3);//获取窗口句柄
        ::GetWindowThreadProcessId(hGame, &dwProcessID);//获取窗口进程ID
        hProcess = ::OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessID);//打开被注入的进程
        if (!hProcess){
                MessageBox("Error:1");
                return;
        }

        BOOL b=::VirtualProtect(idd3, iCount, PAGE_EXECUTE_READWRITE,&dwOldProtect);//修改内存保护方式
        if (!b){
                MessageBox("Error:2");
                return;
        }

        BOOL bWrite = ::WriteProcessMemory(hProcess, idd3, &mFunc, iCount, &dwNumberOfBytes);//写入函数地址
        if (!bWrite){
                MessageBox("Error:3");
                return;
        }
}

但的到的效果是:
0041324A    6C              ins     byte ptr es:[edi], dx
0041324B    1C 41           sbb     al, 41
0041324D    00CC            add     ah, cl
0041324F    CC              int3
00413250    CC              int3
00413251    CC              int3
00413252    CC              int3
00413253    CC              int3
00413254    CC              int3
00413255    CC              int3
00413256    DC11            fcom    qword ptr [ecx]
00413258    0000            add     byte ptr [eax], al

而不是我想要的:
0041324A    8BC0            mov     eax, eax
0041324C    8BC0            mov     eax, eax
0041324E    CC              int3
0041324F    CC              int3
00413250    CC              int3
。。。。。。。。。。。
这样的效果
2011-4-2 23:54
0
雪    币: 692
活跃值: (40)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
9
呵呵,我明白楼主的意思了。

首先,来说说你改后的代码,VirtualProtect这个函数用的不对,你要修改的是另一个进程的内存地址,而这个函数是修改当前调用进程的内存的,换VirtualProtectEx,就行。

其次,你的意思是把某处内存的地址换成你自己的汇编指令,就不能把汇编指令写在函数里,再用WriteProcessMemery来写函数地址,这样,WriteProcessMemery在该内存处写的只是一个jmp指令,就 是跳到函数的执行处,因为这个函数名称单独来用就相当于一个指针,所以按照你的方法,即使修改成功了,该地址处只是一个jmp指令,跳到函数的执行口,而不是mov指令。

我给出我的解决方法吧。我测试成功了。 有什么问题可以去bbs.virusest.net找我。

首先,在OD里看一下程序的这个0x0041324A地址是否有效,如图,其内容如图所示。


在来看修改后的。如图


具体的实现代码如下,我就不多说了:
#include <stdio.h>
#include <windows.h>

const PCHAR gameCaption="SomeApp";

//mov eax, eax
//mov eax,eax
char shellcode[] = {0x8B,0xC0,0x8B,0xC0};


BOOL TestFunc()
{
  int iCount = 1024;
  DWORD dwNumberOfBytes = 0;
  DWORD dwProcessID = 0;
  LPVOID mFunc = CallSelectMonster;
  BOOL fOk = FALSE;
  
  HANDLE hProcess = NULL;
  HANDLE hThread = NULL;
  LPVOID ThreadAddr = NULL;


  __try
  {
    HWND hGame = ::FindWindowA(NULL, gameCaption);
    ::GetWindowThreadProcessId(hGame, &dwProcessID);
    hProcess = ::OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessID);
    if (hProcess == NULL)
      __leave;
	MEMORY_BASIC_INFORMATION mbi = {0};
	if (!::VirtualQueryEx(hProcess, (LPVOID)0x0041324A, &mbi, sizeof(mbi)) == sizeof(mbi))
	{
		DWORD dwError = ::GetLastError();
		__leave;
	}
    //这里看下内存的属性,如果是已提交的,就修改保护属性,否则还得在分配,保留,提交...
	if (mbi.State == MEM_COMMIT)
	{
		DWORD dwOldProtect = 0;
		if (!::VirtualProtectEx(hProcess, (LPVOID)0x0041324A, mbi.RegionSize, PAGE_EXECUTE_READWRITE, &dwOldProtect))
		{
			DWORD dwError = ::GetLastError();
			__leave;
		}
	}  else
	{
		ThreadAddr = ::VirtualAllocEx(hProcess, (LPVOID)0x0041324A, iCount, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
		if (ThreadAddr == NULL)
		{
		  //如果分配失败了,那么由操作系统自己找内存,在来一次
			DWORD i = ::GetLastError();
		  ThreadAddr = VirtualAllocEx(hProcess, NULL, iCount, MEM_COMMIT | MEM_RESERVE,PAGE_EXECUTE_READWRITE);
		  if (ThreadAddr == NULL)
		  {
			  
			printf("error of virtualallocex: %d",::GetLastError());
			__leave;
		  }
		}
	}


    BOOL bWrite = ::WriteProcessMemory(hProcess, (LPVOID)0x0041324A, shellcode, sizeof(shellcode), &dwNumberOfBytes);
    if (!bWrite)
    {
      printf("error of writeprocessmemory: %d",::GetLastError());
      __leave;
    }

    //hThread = ::CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)ThreadAddr, NULL, 0, 0);
    //if (hThread == NULL)
    //{
    //  printf("error of createremotethread: %d", ::GetLastError());
    //  __leave;
    //}

    //::WaitForSingleObject(hThread, INFINITE);

    fOk = TRUE;//到了这里,everything is ok...


  }
  __finally
  {
    if (hProcess != NULL)
    {
      ::CloseHandle(hProcess);
    }



  }

  return fOk;


}


int main()
{
	if (TestFunc())
		printf("ok!");
	else
		printf("failed!");

	getchar();
	return 0;
}
上传的附件:
2011-4-3 11:25
0
雪    币: 1602
活跃值: (14)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
10
VirtualQueryEx(
VirtualProtectEx
为什么最后又没有恢复内存地属性?
感谢楼上如此认真地对待问题
2011-4-4 08:44
0
雪    币: 692
活跃值: (40)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
11
恩,你说的对,如果修改了原来的内存属性,确实应该恢复该块内存的属性,内存管理涉及到的问题很多,感谢提醒。
2011-4-4 12:49
0
游客
登录 | 注册 方可回帖
返回
//