// pokerproxy.cpp : Defines the entry point for the application. // #include "stdafx.h" #include "pokerproxy.h" LRESULT CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam); int gimmeprivs() { // enable SE_DEBUG_NAME and try again TOKEN_PRIVILEGES Priv, PrivOld; DWORD cbPriv = sizeof(PrivOld); HANDLE hToken; // get current thread token if (!OpenThreadToken(GetCurrentThread(), TOKEN_QUERY|TOKEN_ADJUST_PRIVILEGES, FALSE, &hToken)) { if (GetLastError() != ERROR_NO_TOKEN) return FALSE; // revert to the process token, if not impersonating if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY|TOKEN_ADJUST_PRIVILEGES, &hToken)) return FALSE; } // _ASSERTE(ANYSIZE_ARRAY > 0); Priv.PrivilegeCount = 1; Priv.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &Priv.Privileges[0].Luid); // try to enable the privilege if (!AdjustTokenPrivileges(hToken, FALSE, &Priv, sizeof(Priv), &PrivOld, &cbPriv)) { int dwError = GetLastError(); CloseHandle(hToken); return SetLastError(dwError), FALSE; } if (GetLastError() == ERROR_NOT_ALL_ASSIGNED) { // the SE_DEBUG_NAME privilege is not in the caller's token CloseHandle(hToken); return SetLastError(ERROR_ACCESS_DENIED), FALSE; } return TRUE; } HINSTANCE hInst; int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow) { hInst = hInstance; WORD wVersionRequested = MAKEWORD( 2, 2 ); WSADATA wsaData; WSAStartup( wVersionRequested, &wsaData ); DialogBox(hInstance, (LPCTSTR)IDD_ABOUTBOX, NULL, (DLGPROC)About); return 1; } unsigned int proxy_ip[4]; unsigned int proxy_port = 8080; HWND hStatus, hAttach; typedef struct { unsigned char under_retaddr; DWORD connect_handle; unsigned char conn_to[4]; } conn_request; bool WINAPI attachToClient(int n) { char buf[1024]; HWND wnd; wnd = FindWindow(NULL, "Connecting to Server..."); if (wnd == NULL) wnd = FindWindow(NULL, "Not Connected"); if (wnd == NULL) wnd = FindWindow("SWT_Window0", NULL); if (wnd == NULL) { MessageBox(NULL, "Cannot find the Poker.com client. You need to run the client before attempting to attach to it.", "Cannot find client.", MB_OK); return false; } //RealGetWindowClass(wnd, buf, sizeof(buf)); //MessageBox(NULL, buf, "Window class", MB_OK); DWORD pid; GetWindowThreadProcessId(wnd, &pid); if (!DebugActiveProcess(pid)) { gimmeprivs(); if (!DebugActiveProcess(pid)) { sprintf(buf, "cannot attach to process %i err=%i\n", pid, GetLastError()); SendMessage(hStatus, LB_ADDSTRING, 0, (LPARAM)buf); return false; } } DebugSetProcessKillOnExit(FALSE); sprintf(buf, "attached to process %i", pid); SendMessage(hStatus, LB_ADDSTRING, 0, (LPARAM)buf); EnableWindow(hAttach, FALSE); CONTEXT context; PROCESS_INFORMATION pi; HANDLE hThread; DEBUG_EVENT DebugEv; // debugging event information DWORD dwContinueStatus = DBG_CONTINUE; // exception continuation bool first = true; ULONG64 stepFrom = 0; unsigned char stop = 0xcc; FARPROC a_connect = GetProcAddress(GetModuleHandle("ws2_32.dll"), "connect"); unsigned char undercc; std::map > retaddrs; for(;;) { // Wait for a debugging event to occur. The second parameter indicates // that the function does not return until a debugging event occurs. if (!WaitForDebugEvent(&DebugEv, 10)) { Sleep(100); continue; } DWORD threadid = DebugEv.dwThreadId; hThread = OpenThread(THREAD_ALL_ACCESS, FALSE, DebugEv.dwThreadId); if (hThread == NULL) break; FARPROC addr = (FARPROC)DebugEv.u.Exception.ExceptionRecord.ExceptionAddress; // Process the debugging event code. switch (DebugEv.dwDebugEventCode) { case EXCEPTION_DEBUG_EVENT: // Process the exception code. When handling // exceptions, remember to set the continuation // status parameter (dwContinueStatus). This value // is used by the ContinueDebugEvent function. switch (DebugEv.u.Exception.ExceptionRecord.ExceptionCode) { case EXCEPTION_ACCESS_VIOLATION: // First chance: Pass this on to the system. // Last chance: Display an appropriate error. //printf("access violation at %x\n", addr); TerminateProcess(pi.hProcess, 1); return false; case EXCEPTION_BREAKPOINT: // First chance: Display the current // instruction and register values. // printf("breakpoint at addr %x\n", addr); if (first) { first = false; SIZE_T nread; ReadProcessMemory(pi.hProcess, (LPVOID)a_connect, &undercc, 1, &nread); WriteProcessMemory(pi.hProcess, (LPVOID)a_connect, &stop, 1, &nread); } else { SIZE_T nread, written; if (addr != a_connect) { if (retaddrs.find(addr) != retaddrs.end() && retaddrs[addr].find(threadid) != retaddrs[addr].end()) { context.ContextFlags = CONTEXT_ALL; GetThreadContext(hThread, &context); printf("retaddr eax=%i\n", context.Eax); WriteProcessMemory(pi.hProcess, (LPVOID)addr, &retaddrs[addr][threadid].under_retaddr, 1, &written); context.Eip--; SetThreadContext(hThread, &context); if (context.Eax == 0) { HANDLE h; if (DuplicateHandle(pi.hProcess, (HANDLE)retaddrs[addr][threadid].connect_handle, GetCurrentProcess(), &h, 0, FALSE, DUPLICATE_SAME_ACCESS)) { printf("duplicated handle\n"); char buf[1024]; sprintf(buf, "CONNECT %i.%i.%i.%i:443 HTTP/1.0\n\n", retaddrs[addr][threadid].conn_to[0], retaddrs[addr][threadid].conn_to[1], retaddrs[addr][threadid].conn_to[2], retaddrs[addr][threadid].conn_to[3]); printf("sending %s result %i\n", buf, send((SOCKET)h, buf, strlen(buf), 0)); int got = recv((SOCKET)h, buf, 1024, 0); if (got > 0 && got < 1023) { buf[got] = 0; printf("recved %i bytes: %s\n", got, buf); } sprintf(buf, "proxied connection to %i.%i.%i.%i:443", retaddrs[addr][threadid].conn_to[0], retaddrs[addr][threadid].conn_to[1], retaddrs[addr][threadid].conn_to[2], retaddrs[addr][threadid].conn_to[3]); SendMessage(hStatus, LB_ADDSTRING, 0, (LPARAM)buf); } } retaddrs[addr].erase(threadid); if (retaddrs[addr].size() == 0) retaddrs.erase(addr); break; } sprintf(buf, "stopped at unknown address %x\n", (DWORD)addr); SendMessage(hStatus, LB_ADDSTRING, 0, (LPARAM)buf); break; //TerminateProcess(pi.hProcess, 1); //return 1; } context.ContextFlags = CONTEXT_ALL; GetThreadContext(hThread, &context); unsigned char stack[100]; DWORD *d = (DWORD*)&stack; ReadProcessMemory(pi.hProcess, (LPVOID)context.Esp, stack, sizeof(stack), &nread); #if 0 printf("%i %s.%s(%x %x %x %x %x %x %x %x %x %x) ret=%x\n", time(NULL), apis[addr].dll.c_str(), apis[addr].name.c_str(), d[1], d[2], d[3], d[4], d[5], d[6], d[7], d[8], d[9], d[10], d[0]); #endif struct sockaddr_in sin; unsigned char *p = (unsigned char *)&sin.sin_addr; ReadProcessMemory(pi.hProcess, (LPVOID)d[2], &sin, sizeof(sin), &nread); printf("to %i.%i.%i.%i : %i\n", p[0], p[1], p[2], p[3], ((sin.sin_port & 0xff) << 8) | (sin.sin_port >> 8) ); #if 0 if (p[3] == 50) { sin.sin_port = 0xbc01; // 444 } p[0] = 127; p[1] = 0; p[2] = 0; p[3] = 1; WriteProcessMemory(pi.hProcess, (LPVOID)d[2], &sin, sizeof(sin), &nread); #endif if (sin.sin_port == htons(443)) { FARPROC retaddr = (FARPROC)d[0]; retaddrs[retaddr][threadid].conn_to[0] = p[0]; retaddrs[retaddr][threadid].conn_to[1] = p[1]; retaddrs[retaddr][threadid].conn_to[2] = p[2]; retaddrs[retaddr][threadid].conn_to[3] = p[3]; retaddrs[retaddr][threadid].connect_handle = d[1]; ReadProcessMemory(pi.hProcess, (LPVOID)d[0], &retaddrs[retaddr][threadid].under_retaddr, 1, &nread); WriteProcessMemory(pi.hProcess, (LPVOID)d[0], &stop, 1, &nread); p[0] = 203; p[1] = 20; p[2] = 243; p[3] = 20; sin.sin_port = htons(8080); WriteProcessMemory(pi.hProcess, (LPVOID)d[2], &sin, sizeof(sin), &nread); } WriteProcessMemory(pi.hProcess, (LPVOID)addr, &undercc, 1, &written); context.Eip--; context.EFlags |= 256; SetThreadContext(hThread, &context); stepFrom = (ULONG64)addr; } break; case EXCEPTION_DATATYPE_MISALIGNMENT: // First chance: Pass this on to the system. // Last chance: Display an appropriate error. break; case EXCEPTION_SINGLE_STEP: // First chance: Update the display of the // current instruction and register values. if (stepFrom) { unsigned char stop = 0xcc; SIZE_T written; WriteProcessMemory(pi.hProcess, (LPVOID)stepFrom, &stop, 1, &written); stepFrom = 0; } else { printf("single step to %x\n", addr); context.ContextFlags = CONTEXT_ALL; GetThreadContext(hThread, &context); context.EFlags |= 256; SetThreadContext(hThread, &context); } break; case DBG_CONTROL_C: // First chance: Pass this on to the system. // Last chance: Display an appropriate error. break; default: // Handle other exceptions. break; } break; case CREATE_THREAD_DEBUG_EVENT: // As needed, examine or change the thread's registers // with the GetThreadContext and SetThreadContext functions; // and suspend and resume thread execution with the // SuspendThread and ResumeThread functions. break; case CREATE_PROCESS_DEBUG_EVENT: // As needed, examine or change the registers of the // process's initial thread with the GetThreadContext and // SetThreadContext functions; read from and write to the // process's virtual memory with the ReadProcessMemory and // WriteProcessMemory functions; and suspend and resume // thread execution with the SuspendThread and ResumeThread // functions. Be sure to close the handle to the process image // file with CloseHandle. pi.hProcess = DebugEv.u.CreateProcessInfo.hProcess; break; case EXIT_THREAD_DEBUG_EVENT: // Display the thread's exit code. break; case EXIT_PROCESS_DEBUG_EVENT: sprintf(buf, "detached from process"); SendMessage(hStatus, LB_ADDSTRING, 0, (LPARAM)buf); EnableWindow(hAttach, TRUE); return true; // Display the process's exit code. break; case LOAD_DLL_DEBUG_EVENT: // Read the debugging information included in the newly // loaded DLL. Be sure to close the handle to the loaded DLL // with CloseHandle. break; case UNLOAD_DLL_DEBUG_EVENT: // Display a message that the DLL has been unloaded. break; case OUTPUT_DEBUG_STRING_EVENT: // Display the output debugging string. break; } // Resume executing the thread that reported the debugging event. ContinueDebugEvent(DebugEv.dwProcessId, DebugEv.dwThreadId, dwContinueStatus); } sprintf(buf, "detached from process"); SendMessage(hStatus, LB_ADDSTRING, 0, (LPARAM)buf); EnableWindow(hAttach, TRUE); return true; } void readProxyFromRegistry() { proxy_ip[0] = 0; HKEY key; if (RegCreateKey(HKEY_CURRENT_USER, "SOFTWARE\\Poker.com Proxy", &key) != ERROR_SUCCESS) return; char buf[1024]; DWORD sz = sizeof(buf); DWORD t = REG_SZ; if (RegQueryValueEx(key, "Proxy Address", 0, &t, (unsigned char *)buf, &sz) != ERROR_SUCCESS) { RegCloseKey(key); return; } sscanf(buf, "%i.%i.%i.%i", &proxy_ip[0], &proxy_ip[1], &proxy_ip[2], &proxy_ip[3]); sz = sizeof(buf); t = REG_SZ; if (RegQueryValueEx(key, "Proxy Port", 0, &t, (unsigned char *)buf, &sz) != ERROR_SUCCESS) { RegCloseKey(key); return; } sscanf(buf, "%i", &proxy_port); RegCloseKey(key); } void writeProxyToRegistry() { HKEY key; if (RegCreateKey(HKEY_CURRENT_USER, "SOFTWARE\\Poker.com Proxy", &key) != ERROR_SUCCESS) return; char buf[1024]; sprintf(buf, "%i.%i.%i.%i", proxy_ip[0], proxy_ip[1], proxy_ip[2], proxy_ip[3]); RegSetValueEx(key, "Proxy Address", 0, REG_SZ, (unsigned char *)buf, strlen(buf)+1); sprintf(buf, "%i", proxy_port); RegSetValueEx(key, "Proxy Port", 0, REG_SZ, (unsigned char *)buf, strlen(buf)+1); RegCloseKey(key); } // Message handler for about box. LRESULT CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { char buf[1024]; switch (message) { case WM_INITDIALOG: hStatus = GetDlgItem(hDlg, IDC_STATUS); hAttach = GetDlgItem(hDlg, IDC_ATTACH); readProxyFromRegistry(); if (proxy_ip[0]) sprintf(buf, "%i.%i.%i.%i", proxy_ip[0], proxy_ip[1], proxy_ip[2], proxy_ip[3]); else buf[0] = 0; SetDlgItemText(hDlg, IDC_PROXYIP, buf); sprintf(buf, "%i", proxy_port); SetDlgItemText(hDlg, IDC_PROXYPORT, buf); SetClassLong(hDlg, GCL_HICONSM, (LONG)LoadIcon(hInst, (LPCTSTR)IDI_SMALL)); return TRUE; case WM_COMMAND: if (LOWORD(wParam) == IDCANCEL) { EndDialog(hDlg, IDCANCEL); return TRUE; } if (LOWORD(wParam) == IDC_ATTACH) { char proxy[50], port[50]; GetDlgItemText(hDlg, IDC_PROXYIP, proxy, sizeof(proxy)); GetDlgItemText(hDlg, IDC_PROXYPORT, port, sizeof(port)); if (sscanf(proxy, "%i.%i.%i.%i", &proxy_ip[0], &proxy_ip[1], &proxy_ip[2], &proxy_ip[3]) != 4) { MessageBox(NULL, "Please enter the IP address of your SSL proxy\n", "Invalid Proxy Address", MB_OK); break; } if (sscanf(port, "%i", &proxy_port) != 1) { MessageBox(NULL, "Please enter the port of your SSL proxy\n", "Invalid Proxy Port", MB_OK); break; } writeProxyToRegistry(); SendMessage(hStatus, LB_RESETCONTENT, 0, 0); DWORD id; CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)attachToClient, 0, 0, &id); } break; } return FALSE; }