易win10 dll 注入不成功成功注放DLL到游戏后,程序运行...

1259人阅读
最近对一个游戏进行了注入并HookD3D的操作,期间程序一度出现一些游戏不稳定的问题,现在总结一下。
1.注入方式内存方式适用于win7x64非sp1外的版本 (打开进程&申请内存&写入DLL数据&开启远程线程指向内存地址)。
2.线程注入部分系统存在不兼容(未确定) 。
一.初始化流程
由两个DLL组成,可理解为中转。
注入采用vs2010编写win32的动态链接库(只导入kernel32),然后由此DLL从共享内存中获取目录位置,并进行第二个DLL(功能DLL)的载入后并调用初始化函数。
中转的原因如下:
注入后使用LoadLibrary载入时功能DLL,会先将此DLL有的导入函数的相关DLL进行检查并加载,如果系统缺少功能DLL所需的一些DLL,则会造成功能DLL载入失败,返回0,但是如果我们直接将功能DLL注入并调用,如果此时缺少部分系统DLL,则会100%造成被注入程序崩溃。
二.初始化注意事项
1.初始化函数开启一个线程来执行初始化,因为某些函数可能会因为注入方式造成程序主线程卡死。
2.初始化线程不要自行结束,应在返回前使用SuspendThread对自身进行挂起或使用Sleep进行长期的休眠,以免释放线程栈造成的一系列异常。
3.一定要对初始化的每一步做好判断,有一步失败就应停止后续操作参考第2步终止,不建议再次尝试。
4.因为初始化是单独线程,而Hook的执行函数是属于主线程的,所以可能出现Hook完成并已经开始工作,但是初始化缺还未完成导致的错误,这个不要疏忽,应在Hook的函数中增加初始化成功的判断。
三.其他注意事项
1.一定不要注入后在进程中搜索自身,会在xp下产生随机的崩溃问题(即使限制在0xx00FFFFFF范围)(win7下完全不存在此崩溃问题)。
2.最好使用标准win32dll。
3.不应使用需要每次Hook函数后需要恢复的Hook方式,如在操作函数入口时有其他线程正在读写此函数,将会发生不可预知的错误。
4.发布前一定要检查DLL导入函数,是否使用到了其他DLL。
1.不要使用线程死循环Sleep进行计时,会导致不稳定的问题,以及主程序退出时可能发生错误。
2.应使用CreateTimerQueueTimer等函数进行计时。
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:16416次
排名:千里之外
原创:24篇
(1)(1)(4)(3)(1)(2)(2)(4)(1)(1)(1)(1)(2)(2)全系统注入的方法
发布于: 18:07&&&|&&&
62635次阅读
作者: 管理员
&&&|&&&原作者: TP&&&|&&&来自: 原创
1、概述DLL注入技术:&是将一个Dll文件强行加载到目标进程中,比如把外挂dll模块注入到游戏进程,这样做的目的在于方便我们通过这个DLL读写目标进程指令或内存数据,(例如&HOOK游戏函数过程或篡改游戏内存数据实现外挂功能),或以被注入进程的身份去执行一些操作等。全系统注入的优点:利用系统机制实现的全系统进程注入,可绕过比如游戏进程自身的防注入保护机制。比如远线程注入游戏可能会被拦截,但输入法注入,游戏很难拦截。2、消息钩子注入2.1&&&&原理Windows应用程序是基于消息驱动的。应用程序对各种消息响应从而实现各种功能。消息钩子(Message&Hook)是Windows消息处理机制的一个监视点,系统会自动将钩子***到目标进程中达到监视指定类型消息的功能。也就是说通过SetWindowsHookEx&系统会自动将钩子dll注入到目标进程。***钩子的函数原型如下:HHOOK&SetWindowsHookEx(&&&&&&&&&&int&idHook,&//钩子类型&&&&HOOKPROC&lpfn,&&&&HINSTANCE&hMod,&&&&DWORD&dwThreadId);其中dwThreadId为0时,则是全局钩子,即会注入dll到系统所有窗口进程,否则是线程钩子,即只能将dll注入到目标线程所属的进程。当全局钩子时,钩子处理过程HOOKPROC&lpfn&必须位于dll中。2.2&步骤和源码源码将以WH_CBT&钩子为例,实现全系统dll注入。&computer-based&training&(CBT)&基于电脑的训练,比如创建窗口,移动窗口等操作的都会收到通知。&&在以下事件之前,系统都会调用WH_CBT&Hook子程,这些事件包括:1.&激活,建立,销毁,最小化,最大化,移动,改变尺寸等窗口事件;2.&完成系统指令;3.&来自系统消息队列中的移动鼠标,键盘事件;4.&设置输入焦点事件;5.&同步系统消息队列事件。***WH_CBT&钩子将CbtHook.dll注入到notepad进程中的效果:&1.&编写被注入的Dll和钩子处理过程编写一个DLL,并且显式导出CBTProc&()钩子处理过程,主要代码如下:LRESULT&CALLBACK&CBTProc(int&nCode,&WPARAM&wParam,&LPARAM&lParam){char&&&szFileName[MAX_PATH];&if(&(HCBT_CREATEWND&==&nCode)&||&(HCBT_ACTIVATE&==&nCode)&){memset(szFileName,&0,&sizeof(szFileName));::GetModuleFileNameA(NULL,&szFileName,&sizeof(szFileName));DebugPrintA(0,&"Code(%d)&(%s)\n",&nCode,&szFileName);}return&CallNextHookEx(g_hCBT,&nCode,&wParam,&lParam);}&2.&***HOOK&编写一个exe,使用SetWindowsHookEx()向系统***钩子,首先需要将HOOK的DLL&加载到exe本身的进程中,以此得到DLL的模块句柄,再使用GetProcAddress()得到DLL中显示导出的函数MyMessageProc()的函数地址,最后遍历出待注入进程的线程ID,这样SetWindowsHookEx()就可以利用这些参数进行HOOK了。主要代码如下图所示:if&(NULL&==&g_hCbtHook)g_hCbtHook&=&::LoadLibrary(szPathName);&if&(NULL&==&g_hCbtHook){lResult&=&GetLastError();::DebugPrintA(0,&"%s&:&Load&GlobalHook&module&'%s'&fail(%d)\n",&C_ModuleNameA,&szPathName,&lResult);break;}&CBTProc&=&(PCBTPROC)::GetProcAddress(g_hCbtHook,&"CBTProc");if&(NULL&==&g_hCbtHook){lResult&=&GetLastError();::DebugPrintA(0,&"%s&:&Get&GlobalHook&function&fail(%d)\n",&C_ModuleNameA,&lResult);break;}&g_hCBT&=&SetWindowsHookEx(WH_CBT,&CBTProc,&g_hCbtHook,&0);if&(NULL&==&g_hCBT){lResult&=&GetLastError();::DebugPrintA(0,&"%s&:&Set&GlobalHook&fail(%d)\n",&C_ModuleNameA,&lResult);break;}&3.卸载钩子利用LoadLibrary()得到的模块句柄把本身进程的DLL释放掉,代码如下所示:
FreeLibrary(g_hCbtHook);& & & 消息钩子注入只熟悉SetWindowsHookEx()和DLL导出函数就可以很容编写,所以容易实现。2.3&练习使用WH_KEYBOARD键盘钩子注入到Notepad.exe,监视记事本键入的字符。3、注册表注入3.1&原理注册表(Reg)注入原理是利用在Windows&系统中,当REG以下键值中存在有DLL文件路径时,会跟随EXE文件的启动加载这个 & & &DLL文件路径中的DLL文件。AppInit_Dlls注册表:注册表项 HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows&NT\CurrentVersion\Windows中有两个值:& &LoadAppInit_Dlls:键值中指定要注入的DLL& AppInit_Dlls:若其键值为1,则注入LoadAppInit_Dlls中指定的DLL,若为0则不注入。注:(1)LoadAppInit_Dlls中的值当如 & & 果遇到有多个DLL文件时,需要用逗号或者空格隔开多个DLL文件的路径,所以DLL的路径中最好不要有空格。使用范围:任何加载User32.DLL的程序,user32.dll的DllMain会先尝试加载注册表项AppInit_Dlls中的DLL。因为所有的GUI应用程序在启动时都会加载User32.dll,因此这种方法会影响所有的GUI程序。&使用Process&Explorer查看进程模块来确认目标dll是否被注入。3.2&步骤和源码需要解决的就是关于注册表操作的Windows&API了,如下所示:RegOpenKeyEx&&打开注册表键值&&RegQueryValueEx&&查询键值&&RegSetValueEx&&设置键值&&RegCloseKey&&关闭键值&&主要代码如下:BOOL&AddRegItem(CHAR*&szInjectFilePath){//打开键值&&LSTATUS&nReg&=&ERROR_SUCCESS;HKEY hKCHAR&&&&szRegPath[MAX_PATH]&=&"SOFTWARE\\Microsoft\\Windows&NT\\CurrentVersion\\Windows";&nReg&=&RegOpenKeyEx(HKEY_LOCAL_MACHINE,szRegPath,0,KEY_ALL_ACCESS,&hKey);&if&(nReg&!=&ERROR_SUCCESS){return&FALSE;}&//查询键值&&DWORD&dwReadTDWORD&dwReadCTCHAR&szReadBuff[1024]&=&{&0&};nReg&=&RegQueryValueEx(hKey,_T("AppInit_DLLs"),NULL,&dwReadType,(BYTE*)&szReadBuff,&dwReadCount);&if&(nReg&!=&ERROR_SUCCESS){return&FALSE;}&//若dll名称已经在内容中,则不用重复添加&&if&(StrStrI(szReadBuff,szInjectFilePath)){printf("dll&already&in®=%s\n",&szReadBuff);return&FALSE;}&//原来已有内容就加入空格后再附加新dll串&&if&(0&!=&_tcscmp(szReadBuff,&_T(""))){_tcscat_s(szReadBuff,&_T("&"));}&_tcscat_s(szReadBuff,&szInjectFilePath);&//1.把dll路径设置到注册表中&&nReg&=&RegSetValueEx(hKey,_T("AppInit_DLLs"),0,REG_SZ,(CONST&BYTE*)szReadBuff,(_tcslen(szReadBuff)&+&1)*sizeof(TCHAR));//2.启动&注册表加载dll&&BYTE&byEnable[4]&=&{&0x1&};nReg&=&RegSetValueEx(hKey,_T("LoadAppInit_DLLs"),0,REG_DWORD,(CONST&BYTE*)byEnable,4);printf("RegSetValueEx&AppInit_DLLs&=&%s Result=%d\n",&szReadBuff,&nReg);}
3.3&练习& &由于该注册表会注入系统所有的GUI进程,如果我们只对游戏进程感兴趣,那么如何处理,使得目标代码只在游戏进程中运行呢?4、输入法注入4.1&&&&原理&& & &输入法注入是利用当前程序需要输入字符时切换到指定输入法,Windows系统就会把这个输入法需要的Ime文件装载到当前进程中,由于这个Ime文件本质上只是个存放在C:\Windows\System32目录下的特殊的DLL文件,因此我们可以利用这个特性,在Ime文件中使用LoadLibrary()函数待注入的DLL文件。4.2&步骤和源码1、编写Ime文件输入法的Ime文件其实就是个显式导出19个特殊函数的DLL文件。如下图所示:1. ImeConversionList&&&&&&&&&&&//将字符串或字符转换成目标字串&&2. ImeConfigure&&&&&&&&&&&&&&&&//配置当前ime参数函数&&3. ImeDestroy&&&&&&&&&&&&&&&&&&//退出当前使用的IME&&4. ImeEscape&&&&&&&&&&&&&&&&&&&//应用软件访问输入法的接口函数&&5. ImeInquire&&&&&&&&&&&&&&&&&&//启动并初始化当前ime输入法&&6. ImeProcessKey&&&&&&&&&&&&&&&//ime输入键盘事件管理函数&&7. ImeSelect&&&&&&&&&&&&&&&&&&&//启动当前的ime输入法&&8. ImeSetActiveContext&&&&&&&&&//设置当前的输入处于活动状态&&9. ImeSetCompositionString&&&&&//由应用程序设置输入法编码&&10. ImeToAsciiEx&&&&&&&&&&&&&&&&//将输入的键盘事件转换为汉字编码事件&&11. NotifyIME&&&&&&&&&&&&&&&&&&&//ime事件管理函数&&12. ImeRegisterWord&&&&&&&&&&&&&//向输入法字典注册字符串&&13. ImeUnregisterWord&&&&&&&&&&&//删除被注册的字符串&&14. ImeGetRegisterWordStyle&&15. ImeEnumRegisterWord&&16. UIWndProc&&&&&&&&//用户界面接口函数&&17. StatusWndProc&&&&//状态窗口注册函数&&18. CompWndProc&&&&&&//输入编码窗口注册函数&&19. CandWndProc&&&&&&//选择汉字窗口注册函数&&如果想编写功能完整的输入法程序,那么这19个导出函数都需要仔细的研究,但是对于只想实现注入的我们,现在只需要对ImeInquire()有比较深的认识就可以了。ImeInquire()是启动并初始化当前Ime输入法函数,声明如下:BOOL&WINAPI&ImeInquire(LPIMEINFO&lpIMEInfo,LPTSTR&lpszUIClass,LPCTSTR&lpszOption)第一个参数lpIMEInfo比较重要,用于输入对Ime输入法初始化的内容结构,如果这个结构填写错误,就会导致输入法不能正常运行。第二个参数是输入一个class类名,我们需要先使用RegisterClassEx()注册出一个窗口类。1.1&&初始化ImeInquire()主要代码如下所示:BOOL&WINAPI&ImeInquire(LPIMEINFO&lpIMEInfo,LPTSTR&lpszUIClass,LPCTSTR&lpszOption){ //&输入法初始化过程&&&&lpIMEInfo-&dwPrivateDataSize&=&0;&//系统根据它为INPUTCONTEXT.hPrivate分配空间&&&&&lpIMEInfo-&fdwProperty&=&IME_PROP_KBD_CHAR_FIRST&|&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&IME_PROP_IGNORE_UPKEYS&|
&IME_PROP_END_UNLOAD;&&&&&&lpIMEInfo-&fdwConversionCaps&=&IME_CMODE_FULLSHAPE&|
IME_CMODE_NATIVE;&&&&&lpIMEInfo-&fdwSentenceCaps&=&IME_SMODE_NONE;&&&&lpIMEInfo-&fdwUICaps&=&UI_CAP_2700; lpIMEInfo-&fdwSCSCaps&=&0;&&&&lpIMEInfo-&fdwSelectCaps&=&SELECT_CAP_CONVERSION;&&&&_tcscpy(lpszUIClass,CLSNAME_UI);&&//&注意该输入法基本窗口类必须注册,否则输入法不能正常运行&&&&return&TRUE;}&1.2&&注册输入法窗口类使用RegisterClassEx注册窗口类,主要代码如下://************************************************************// 基本输入法窗口UI类注册//************************************************************BOOL&ImeClass_Register(HINSTANCE&hInstance){&&&&WNDCLASSEX& &&&&//&&&&//®ister&class&of&UI&window.&&&&//&&&&wc.cbSize&&&&&&&&&=&sizeof(WNDCLASSEX);&&&&wc.style&&&&&&&&&&=&CS_INPUTSTAR&|&CS_IME;&&&&wc.lpfnWndProc&&&&=&UIWndP&&&&wc.cbClsExtra&&&&&=&0;&&&&wc.cbWndExtra&&&&&=&2&*&sizeof(LONG);&&&&wc.hInstance&&&&&&=&hInstance;&&&&wc.hCursor&&&&&&&&=&LoadCursor(&NULL,&IDC_ARROW&);&&&&wc.hIcon&&&&&&&&&&=&NULL;&&&&wc.lpszMenuName&&&=&(LPTSTR)NULL;&&&&wc.lpszClassName&&=&CLSNAME_UI;&&&&wc.hbrBackground&&=&NULL;&&&&wc.hIconSm&&&&&&&&=&NULL; &&&&if(&!RegisterClassEx(&(LPWNDCLASSEX)&wc&)&)&&&&&&&&return&FALSE;
return&TRUE;}&&1.3&&Ime的DllMain注册窗口,并加载要被注入的dll主要代码如下:BOOL&WINAPI&DllMain(HINSTANCE&hinstDLL,DWORD&fdwReason,LPVOID&lpvReserved){&&&switch(fdwReason)&&&&{&&&&&&case&DLL_PROCESS_ATTACH:
&&&OutputDebugString(_T("ime&DLL_PROCESS_ATTACH"));
&&&MyLoadCilentDLLFun();
&&if(!ImeClass_Register(hinstDLL))&
&&return&FALSE;&&&//&DLL加载时注册必须的UI基本窗口类
&&break;&&&&} return&true;}&1.4&&IME版本信息编写DLL时需要注意,当作IME文件的Dll需要有版本信息,Version资源中FILETYPE为VFT_DRV,&FILESUBTYPE为VFT2_DRV_INPUTMETHOD,否则调用ImmInstallIME***时会失败。2、***输入法***输入法的基本逻辑就是将自己编写的输入法设置为系统默认输入法,这样系统中所有进程就会默认加载这个恶意输入法程序。首先需要得到系统当前的默认的输入法,以便恢复时使用。然后需要将ime文件拷贝到C:\Windows\System32目录下,最后将装载成功后将自己的输入法设置成为默认输入法,主要代码如下:HKL&ImmInstallI(CString&CurrentImeFile,CString&SymImeFile){ &HKL&MYhkl&=&0; &HKL&oldhkl=0;//用于卸载本输入法的时候恢复 &SystemParametersInfo(
&SPI_GETDEFAULTINPUTLANG,
&); &CopyFile(CurrentImeFile,SymImeFile,FALSE);//重写已存在的文件 &MYhkl&=&ImmInstallIME(SymImeFile,L"IME注入输入法");&&&&&return&MY}void&MSetIMEIsDefInput(HKL&Immhkl){ BOOL&bDefault=FALSE; Sleep(1000); if&(ImmIsIME(Immhkl)) {
if(g_IsDefaultIME)
{ //bDefault=SystemParametersInfo(SPI_SETDEFAULTINPUTLANG,0,&Immhkl,SPIF_SENDCHANGE||SPIF_UPDATEINIFILE);&//设置为默认输入法
bDefault=SystemParametersInfo(SPI_SETDEFAULTINPUTLANG,0,&Immhkl,SPIF_SENDWININICHANGE);
} }}&3、编写卸载输入法当不再需要注入时,我们就需要卸载输入法。卸载输入法时需要先判定系统当前的输入法不是其原有默认输入法,确认无误后将系统的默认输入法恢复后,再将恶意输入法卸载即可,主要代码如下:::SystemParametersInfo(&& &&&&&&&&SPI_SETDEFAULTINPUTLANG,&& &&&&&&&&0,&&&&&&&&&&&m_retV,&& &&&&&&&&SPIF_SENDWININICHANGE);&&&&&&if&(UnloadKeyboardLayout(m_hImeFile))&& &&&&{&& &&&&&&&&MessageBox(_T("输入法卸载成功"));&&&&&&&&&&}&&&输入法注入的实现需要对输入法IME文件的生成有所了解,API使用较多,所以实现起来比较难,但是由于系统存在多个输入法,被注入进程很难判别当前是可信赖输入法还是用于注入的恶意输入法,所以难以阻止,大大提高了注入的几率。5、三种方法优缺点对比消息钩子: 编写简单。xp上可以注入dll到系统进程,但win7上,由于Session&0&隔离机制,不能注入系统进程。同时由于权限隔离,不能注入到高等级的进程中。注册表: 简单,但只能注入GUI进程输入法: 复杂,但可注入任何接受输入法的进程。

参考资料

 

随机推荐