精简版:
我正在尝试使用调试权限打开一个进程句柄并定义一个指向被调试对象内存中对象的指针。
长版
我在毕业的最后一年是一名计算机科学大学的学生,我的任务是构建一个应用程序,该应用程序应该用于下一代学生的教育目的。
你可能会问,我为什么在这里寻求帮助?好吧,目标平台是Windows,不幸的是我对WinAPI一无所知......
好的,这是基本要求:
- 编程语言:C++
- 平台:Windows(7 专业版)
- 使用的 IDE:Visual Studio 2012
- 如果它们对于简化开发不是必需的,则无需额外的库
该应用程序将用于什么用途?
使用这个应用程序,学生将学习处理地址,在这种情况下是静态的:被调试进程会有一些静态指针,这些指针会导致其他指针本身形成一个多维指针。学生们必须使用一些调试技术(这不是我的工作的一部分!)找到这些基地址,并尝试在这些指针的末尾找到值。
导师将使用我的应用程序来随机更改被调试进程中的值和/或结构。
一些搜索确实产生了第一个答案:使用ReadProcessMemory
andWriteProcessMemory
可以轻松更改另一个进程的内存中的值,而无需获得调试权限。
然而,我的导师想要的是能够定义指针(比如说 unsigned int),它应该指向被调试进程的内存空间,有效地保存我之前写的基地址。他们真的很想要这个,我什至不能和他们说这个,所以我最后还是坚持这样做......
究竟应该怎么做?
好吧,如果以下(伪)代码有效,我就完成了我的任务:
grantThisProcessDebugPrivileges();
openAnotherProcessWhileItsRunning("targetProcess.exe");
unsigned int * targetValue = (unsigned int*) 0xDE123F00;
// or even
myCustomClass * targetClass = (myCustomClass*) 0xDE123F00;
其中地址 0xDE123F00 位于 targetProcess.exe 的内存空间中。
我知道这是可能的,否则不会有调试器可以显示这些信息。
到目前为止我做了什么(或尝试过......)
好的,事情是:我真的很困惑我是否必须在打开目标进程之前激活我的应用程序的调试权限,在打开之后执行它还是给目标进程这些权限。
于是我在 MSDN 中找到了一个例子,并尝试实现它:
BOOL SetPrivilege(
HANDLE hToken, // token handle
LPCTSTR Privilege, // Privilege to enable/disable
BOOL bEnablePrivilege // TRUE to enable. FALSE to disable
)
{
TOKEN_PRIVILEGES tp;
LUID luid;
TOKEN_PRIVILEGES tpPrevious;
DWORD cbPrevious=sizeof(TOKEN_PRIVILEGES);
if(!LookupPrivilegeValue( NULL, Privilege, &luid )) return FALSE;
//
// first pass. get current privilege setting
//
tp.PrivilegeCount = 1;
tp.Privileges[0].Luid = luid;
tp.Privileges[0].Attributes = 0;
AdjustTokenPrivileges(
hToken,
FALSE,
&tp,
sizeof(TOKEN_PRIVILEGES),
&tpPrevious,
&cbPrevious
);
if (GetLastError() != ERROR_SUCCESS) return FALSE;
//
// second pass. set privilege based on previous setting
//
tpPrevious.PrivilegeCount = 1;
tpPrevious.Privileges[0].Luid = luid;
if(bEnablePrivilege) {
tpPrevious.Privileges[0].Attributes |= (SE_PRIVILEGE_ENABLED);
}
else {
tpPrevious.Privileges[0].Attributes ^= (SE_PRIVILEGE_ENABLED &
tpPrevious.Privileges[0].Attributes);
}
AdjustTokenPrivileges(
hToken,
FALSE,
&tpPrevious,
cbPrevious,
NULL,
NULL
);
if (GetLastError() != ERROR_SUCCESS) return FALSE;
return TRUE;
};
而在我的主要:
HANDLE mainToken;
// I really don't know what this block of code does :<
if(!OpenThreadToken(GetCurrentThread(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, FALSE, &mainToken))
{
if (GetLastError() == ERROR_NO_TOKEN)
{
if (!ImpersonateSelf(SecurityImpersonation))
return 1;
if(!OpenThreadToken(GetCurrentThread(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, FALSE, &mainToken)){
cout << GetLastError();
return 1;
}
}
else
return 1;
}
if (!SetPrivilege(mainToken, SE_DEBUG_NAME, true))
{
CloseHandle(mainToken);
cout << "Couldn't set DEBUG MODE: " << GetLastError() << endl;
return 1;
};
unsigned int processID = getPID("targetProcess.exe");
HANDLE hproc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, processID);
if (hproc == NULL)
{
cout << "Couldn't open the process" << endl;
return 1;
};
unsigned int * theValue = (unsigned int*) 0xDE123F;
好的,这段代码运行没有任何错误, SetPrivilege 返回 TRUE 所以我猜它确实 set SE_DEBUG_NAME
,我认为这是我需要设置的标志。
但是,例如,在输出 的取消引用值之后theValue
,应用程序崩溃并显示访问冲突消息,这表明我的方法不起作用。我确实特别注意以管理员权限启动 VisualStudio 调试器(否则 SetPrivilege 失败)。
我在这里真的一无所知,我不知道设置是否SE_DEBUG_NAME
是正确的方法这一事实增加了我的整体困惑。
我希望你能帮助我:) 我对应用程序的具体要求束手无策,如果你有想法使用整个不同的方法来实现我的目标,你可以自由地启发我,但我不能把它呈现给我的上级,这样只会增加我的知识:D