MSN 双开工具源代码
网上偶然拾得本人于 2006 年所写的 **MSN Messenger** 双/多开工具的源代码。此即时通讯软件早于 2013 年便已停止服务,而今再看昔日所写代码不甚感慨,遂记录于此,以兹纪念。
c++#pragma comment(linker,"/subsystem:windows")
#pragma comment(linker,"/align:4096")
#define MSN_APP "\\MSN Messenger\\msnmsgr.exe"
#define TF_BIT 0x100
#include <windows.h>
#include <map>
using namespace std;
map <DWORD, HANDLE> ThreadList;
HANDLE hTargetProcess;
DWORD dwMainThreadId;
DWORD GetRetAddress( LPVOID lpBsp )
{
DWORD dwBytesRead, dwRetAddress;
if ( ReadProcessMemory( hTargetProcess, lpBsp, &dwRetAddress, sizeof(DWORD), &dwBytesRead ) )
{
return(dwRetAddress);
}
return(NULL);
}
LPVOID g_lpGetLastErrorRet;
int SetHook( bool bSet )
{
static bool bInitial;
static LPVOID lpGetLastErrorRet;
BYTE bytOriginalOpCode = 0xC3;
if ( !bInitial )
{
BYTE lpCode[32];
LPVOID lpGetLastError;
lpGetLastError = GetProcAddress( GetModuleHandle( "kernel32.dll" ), "GetLastError" );
DWORD dwBytesRead;
/* ReadProcessMemory(hTargetProcess,lpGetLastError,&bytOriginalOpCode,sizeof(BYTE),&dwBytesRead); */
ReadProcessMemory( hTargetProcess, lpGetLastError, &lpCode, sizeof(lpCode), &dwBytesRead );
for ( int i = 0; i < 32; i++ )
{
if ( 0xC3 == lpCode[i] )
{
g_lpGetLastErrorRet = lpGetLastErrorRet = (LPVOID) ( ( (DWORD) lpGetLastError) + i);
break;
}
}
bInitial = true;
}
BYTE bytBreakOpCode = 0xCC;
DWORD dwBytesReadWrite;
MEMORY_BASIC_INFORMATION mbi;
VirtualQueryEx( hTargetProcess, lpGetLastErrorRet, &mbi, sizeof(mbi) );
VirtualProtectEx( hTargetProcess, mbi.BaseAddress, mbi.RegionSize, PAGE_EXECUTE_READWRITE, &mbi.Protect );
if ( bSet )
{
WriteProcessMemory( hTargetProcess, lpGetLastErrorRet, &bytBreakOpCode, sizeof(BYTE), &dwBytesReadWrite );
}else{
WriteProcessMemory( hTargetProcess, lpGetLastErrorRet, &bytOriginalOpCode, sizeof(BYTE), &dwBytesReadWrite );
}
FlushInstructionCache( hTargetProcess, lpGetLastErrorRet, sizeof(BYTE) );
return(TRUE);
}
int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow )
/* int main() */
{
char lpApplication[MAX_PATH];
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory( &si, sizeof(si) );
ZeroMemory( &pi, sizeof(pi) );
si.cb = sizeof(si);
GetEnvironmentVariable( "ProgramFiles", lpApplication, MAX_PATH );
strcat( lpApplication, MSN_APP );
if ( !CreateProcess( lpApplication, NULL, NULL, NULL, FALSE, DEBUG_ONLY_THIS_PROCESS, NULL, NULL, &si, &pi ) )
{
MessageBox( GetDesktopWindow(), "Fail to launch \"msnmsgr.exe\"!", "Error", MB_OK | MB_ICONSTOP );
return(FALSE);
}
DEBUG_EVENT de;
BOOL bContinue = TRUE, bInitial = FALSE;
DWORD dwContinueStatus;
CONTEXT context;
ZeroMemory( &context, sizeof(context) );
UINT uHookCount = 0;
while ( bContinue )
{
bContinue = WaitForDebugEvent( &de, INFINITE );
dwContinueStatus = DBG_CONTINUE;
switch ( de.dwDebugEventCode )
{
case CREATE_THREAD_DEBUG_EVENT:
ThreadList[de.dwThreadId] = de.u.CreateThread.hThread;
break;
case CREATE_PROCESS_DEBUG_EVENT:
hTargetProcess = de.u.CreateProcessInfo.hProcess;
ThreadList[de.dwThreadId] = de.u.CreateProcessInfo.hThread;
dwMainThreadId = de.dwThreadId;
break;
case EXIT_PROCESS_DEBUG_EVENT:
bContinue = FALSE;
break;
case EXCEPTION_DEBUG_EVENT:
switch ( de.u.Exception.ExceptionRecord.ExceptionCode )
{
case EXCEPTION_SINGLE_STEP:
if ( uHookCount < 3 )
{
context.ContextFlags = CONTEXT_FULL;
if ( GetThreadContext( ThreadList[de.dwThreadId], &context ) )
{
SetHook( TRUE );
}
}
break;
case EXCEPTION_BREAKPOINT:
dwContinueStatus = de.u.Exception.dwFirstChance ? DBG_CONTINUE : DBG_EXCEPTION_NOT_HANDLED;
if ( !bInitial )
{
SetHook( TRUE );
bInitial = TRUE;
}
context.ContextFlags = CONTEXT_FULL;
if ( GetThreadContext( ThreadList[de.dwThreadId], &context ) )
{
if ( (context.Eip - 1) == (DWORD) g_lpGetLastErrorRet )
{
/* printf("Return Address: 0x%08X\n",GetRetAddress((LPVOID)context.Esp)); */
if ( 0x00700000 > GetRetAddress( (LPVOID) context.Esp ) && de.dwThreadId == dwMainThreadId )
{
if ( ERROR_ALREADY_EXISTS == context.Eax )
{
context.Eax = 0;
uHookCount++;
}
}
SetHook( FALSE );
context.Eip--;
context.EFlags |= TF_BIT;
SetThreadContext( ThreadList[de.dwThreadId], &context );
dwContinueStatus = DBG_CONTINUE;
}
}
break;
default: dwContinueStatus = DBG_EXCEPTION_NOT_HANDLED;
}
break;
/* default: */
}
ContinueDebugEvent( de.dwProcessId, de.dwThreadId, dwContinueStatus );
}
CloseHandle( pi.hProcess );
CloseHandle( pi.hThread );
return(TRUE);
}
MSN Messenger 通过创建全局互斥量来保证系统中同时只能运行一个进程。伪代码如下:
c++hMutex = CreateMutex(NULL, FALSE, "MSNMessengerIsRunning");
if (GetLastError() == ERROR_ALREADY_EXISTS)
{
// MSN Messenger 已启动,本进程即将退出
ExitProcess();
}
工具的破解原理是:通过 Hook GetLastError
,修改该 API 的返回值,从而欺骗 MSN 进程,以绕过限制。