When I was working on a proxy a while ago I needed a way redirect the connections from conquer client to my proxy. There is a couple of ways to achieve this but I choose detours (2.1). However I noticed that there was a lack of tutorials on how to actually start using Microsoft detours (or I couldn't use Google properly, which is also possible :D). So here's a little step-by-step tutorial how to start using them and I will also show how to detour Connect and ShellExecute functions.
Step 1 - Download the detours package
You can download the detours package from [Only registered and activated users can see links. Click Here To Register...]. Scroll down a bit and you should see Detours Express 2.1 this is the version you should download (unless you plan to get a license for it, which costs a "few" dollars.)
Step 2 - Install the detours package
Installing detours is pretty much the same as installing some other program. Just follow the instructions and unless you know what you're doing, don't change the installation directory. By default it should be C:\Program Files\Microsoft Research\Detours Express 2.1
Step 3 - Compiling the detours package
There's basically two ways to compile the detours package. The first way is to use program called "nmake" (which didn't work for me so we're not discussing it :P). The second way is to compile it using a C++ compiler. I'll be using Visual Studio 2010.
What you should now do is to create a new Win32 Project, name it anything you like, it doesn't really matter. The project type should be changed to Static Library and the Precompiled Header should be unchecked.
When the project is created you need to add the detour files into the project. This is done by right clicking the project -> Add -> Existing Item. The files are located where ever you installed the detours to. The default path is C:\Program Files\Microsoft Research\Detours Express 2.1\src. When you've navigated to the folder, choose everything else but the Makefile-file.
Visual Studio should automatically place the files in the correct filter systems (Header, Resource, Source) according to the file type (.h, .rc, .cpp). After these files have been added to the project successfully you should navigate to detoured.cpp and comment out the DllMain part
to
IF Visual Studio gives error Must define one of DETOURS_X86, DETOURS_X64, or DETOURS_IA64 you need to go to Project -> Properties -> Configuration Properties -> C/C++ -> Preprocessor -> Preprocessor definitions and add either DETOURS_X86 if you're running on a 32-bit platform and DETOURS_X64 if you're using 64-bit platform.
Now the project should build just fine and the output should be a file %PROJECT_NAME%.lib where PROJECT_NAME is the name you gave to this project earlier.
Step 4 - Using detours
In order to use detours you need to create a new Win32 Project and type of DLL. The actual detouring isn't hard once you grasp the idea behind it so it's probably easier to show the code.
DllMain is the function which gets called when the dll is attached, detached etc. I've only added the attach part. Basically the only thing that matters is the DetourAttach function which takes two parameters: PVOID *ppPointer and PVOID Detour. The first parameter is the function you wish to detour and the second parameter is your own function.
The declaration of the OriginalShell might look a bit wierd and it's called function pointer. (If you're interested in function pointers :D take a look at [Only registered and activated users can see links. Click Here To Register...])
This basically creates a function pointer OriginalShell which points to ShellExecuteA (which is the function that conquer uses to create the annoying internet popup at exiting.)
The detour function is much "simpler" to understand.
This basically just compares the lpFile -parameter that was passed to the ShellExecuteA (which we detoured to our function) with the signout address for conquer. At the end where we return the OriginalShell function value what we basically do is we call the ShellExecuteA with the parameters (which may have been modified) and the return the value and continue program execution.
Step 5 - Injecting DLL
Creating a DLL isn't enough. You will also need to inject it to Conquer either with already built injector or create your own. Here's a sample code to do it on your own in C#.
and the imports
I basically ripped this off from a website I found and I realise the imports are "wrong" (definitions are bit off) but it works.
P.S I'll add pictures if this wall of text is too boring to read.
Step 1 - Download the detours package
You can download the detours package from [Only registered and activated users can see links. Click Here To Register...]. Scroll down a bit and you should see Detours Express 2.1 this is the version you should download (unless you plan to get a license for it, which costs a "few" dollars.)
Step 2 - Install the detours package
Installing detours is pretty much the same as installing some other program. Just follow the instructions and unless you know what you're doing, don't change the installation directory. By default it should be C:\Program Files\Microsoft Research\Detours Express 2.1
Step 3 - Compiling the detours package
There's basically two ways to compile the detours package. The first way is to use program called "nmake" (which didn't work for me so we're not discussing it :P). The second way is to compile it using a C++ compiler. I'll be using Visual Studio 2010.
What you should now do is to create a new Win32 Project, name it anything you like, it doesn't really matter. The project type should be changed to Static Library and the Precompiled Header should be unchecked.
When the project is created you need to add the detour files into the project. This is done by right clicking the project -> Add -> Existing Item. The files are located where ever you installed the detours to. The default path is C:\Program Files\Microsoft Research\Detours Express 2.1\src. When you've navigated to the folder, choose everything else but the Makefile-file.
Visual Studio should automatically place the files in the correct filter systems (Header, Resource, Source) according to the file type (.h, .rc, .cpp). After these files have been added to the project successfully you should navigate to detoured.cpp and comment out the DllMain part
PHP Code:
BOOL WINAPI DllMain(HINSTANCE hinst, DWORD dwReason, LPVOID reserved)
{
(void)reserved;
if (dwReason == DLL_PROCESS_ATTACH) {
s_hDll = hinst;
DisableThreadLibraryCalls(hinst);
}
return TRUE;
}
PHP Code:
/*
BOOL WINAPI DllMain(HINSTANCE hinst, DWORD dwReason, LPVOID reserved)
{
(void)reserved;
if (dwReason == DLL_PROCESS_ATTACH) {
s_hDll = hinst;
DisableThreadLibraryCalls(hinst);
}
return TRUE;
}
*/
Now the project should build just fine and the output should be a file %PROJECT_NAME%.lib where PROJECT_NAME is the name you gave to this project earlier.
Step 4 - Using detours
In order to use detours you need to create a new Win32 Project and type of DLL. The actual detouring isn't hard once you grasp the idea behind it so it's probably easier to show the code.
PHP Code:
// dllmain.cpp : Defines the entry point for the DLL application.
#include "stdafx.h"
#include <WinSock2.h>
#include <shellapi.h>
#include "Detours\\detours.h"
#pragma comment(lib, "shell32.lib")
#pragma comment(lib, "ws2_32.lib")
#pragma comment(lib, "Detours\\DetoursLibrary.lib")
int (WINAPI *OriginalConnect)(SOCKET s, const sockaddr *name, int len) = connect;
HINSTANCE (WINAPI *OriginalShell)(HWND hWnd, LPCSTR lpOperation, LPCSTR lpFile, LPCSTR lpParameters, LPCSTR lpDirectory, int nShowCmd) = ShellExecuteA;
HINSTANCE WINAPI DetouredShell(HWND hWnd, LPCSTR lpOperation, LPCSTR lpFile, LPCSTR lpParameters, LPCSTR lpDirectory, int nShowCmd)
{
if(strcmp("http://co.91.com/signout/", lpFile) == 0)
{
lpFile = "http://www.google.com";
}
return OriginalShell(hWnd, lpOperation, lpFile, lpParameters, lpDirectory, nShowCmd);
}
int WINAPI DetouredConnect(SOCKET s, const sockaddr *name, int len)
{
return OriginalConnect(s, name, len);
}
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
switch(ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
{
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
DetourAttach(&(PVOID&)OriginalConnect, DetouredConnect);
DetourAttach(&(PVOID&)OriginalShell, DetouredShell);
DetourTransactionCommit();
} break;
}
return TRUE;
}
The declaration of the OriginalShell might look a bit wierd and it's called function pointer. (If you're interested in function pointers :D take a look at [Only registered and activated users can see links. Click Here To Register...])
PHP Code:
HINSTANCE (WINAPI *OriginalShell)(HWND hWnd, LPCSTR lpOperation, LPCSTR lpFile, LPCSTR lpParameters, LPCSTR lpDirectory, int nShowCmd) = ShellExecuteA;
The detour function is much "simpler" to understand.
PHP Code:
HINSTANCE WINAPI DetouredShell(HWND hWnd, LPCSTR lpOperation, LPCSTR lpFile, LPCSTR lpParameters, LPCSTR lpDirectory, int nShowCmd)
{
if(strcmp("http://co.91.com/signout/", lpFile) == 0)
{
lpFile = "http://www.google.com";
}
return OriginalShell(hWnd, lpOperation, lpFile, lpParameters, lpDirectory, nShowCmd);
}
Step 5 - Injecting DLL
Creating a DLL isn't enough. You will also need to inject it to Conquer either with already built injector or create your own. Here's a sample code to do it on your own in C#.
PHP Code:
using System;
using System.Runtime.InteropServices;
using System.Diagnostics;
namespace ConquerProxy
{
public class ConquerInjector
{
private string Dll;
private IntPtr hProcess;
public ConquerInjector(string Dll)
{
this.Dll = Dll;
}
private bool FetchID(string Name)
{
Process[] Processes = Process.GetProcessesByName(Name);
if (Processes.Length == 0)
return false;
hProcess = Kernel32.OpenProcess(0x1F0FFF, 1, Processes[0].Id);
if (hProcess == IntPtr.Zero)
{
Console.WriteLine("OpenProcess(0x1F0FFF, 1, ID) failed with following error: " + Marshal.GetLastWin32Error());
return false;
}
return true;
}
public bool Attach(string ProcessName)
{
if (FetchID(ProcessName))
{
uint Length = (uint)(Dll.Length + 1);
IntPtr AllocatedMemory = Kernel32.VirtualAllocEx(hProcess, IntPtr.Zero, Length, 0x1000, 0x40);
IntPtr BytesWritten = IntPtr.Zero;
if (Kernel32.WriteProcessMemory(hProcess, AllocatedMemory, Dll, Length, BytesWritten))
{
UIntPtr hLoadLibrary = Kernel32.GetProcAddress(Kernel32.GetModuleHandle("Kernel32.dll"), "LoadLibraryA");
if (hLoadLibrary != UIntPtr.Zero)
{
uint ThreadID = 0;
IntPtr hThread = Kernel32.CreateRemoteThread(hProcess, IntPtr.Zero, 0, hLoadLibrary, AllocatedMemory, 0, out ThreadID);
if (hThread != IntPtr.Zero)
{
Kernel32.WaitForSingleObject(hThread, 2000);
Kernel32.CloseHandle(hThread);
Kernel32.VirtualFreeEx(hProcess, AllocatedMemory, UIntPtr.Zero, 0x8000);
return true;
}
return false;
}
return false;
}
return false;
}
return false;
}
}
}
PHP Code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
namespace ConquerProxy
{
public class Kernel32
{
[DllImport("Kernel32.dll")]
public static extern IntPtr CreateRemoteThread(IntPtr hProcess, IntPtr lpThreadAttributes, uint dwStackSize, UIntPtr lpStartAddress, IntPtr lpParameter, uint dwCreationFlags, out uint lpThreadId);
[DllImport("Kernel32.dll")]
public static extern IntPtr OpenProcess(UInt32 dwDesiredAccess, Int32 bInheritHandle, Int32 dwProcessId);
[DllImport("Kernel32.dll")]
public static extern Int32 CloseHandle(IntPtr hObject);
[DllImport("Kernel32.dll", SetLastError = true, ExactSpelling = true)]
public static extern bool VirtualFreeEx(IntPtr hProcess, IntPtr lpAddress, UIntPtr dwSize, uint dwFreeType);
[DllImport("Kernel32.dll", CharSet = CharSet.Ansi, ExactSpelling = true)]
public static extern UIntPtr GetProcAddress(IntPtr hModule, string procName);
[DllImport("Kernel32.dll", SetLastError = true, ExactSpelling = true)]
public static extern IntPtr VirtualAllocEx(IntPtr hProcess, IntPtr lpAddress, uint dwSize, uint flAllocationType, uint flProtect);
[DllImport("Kernel32.dll")]
public static extern bool WriteProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, string lpBuffer, uint nSize, IntPtr lpNumberOfBytesWritten);
[DllImport("Kernel32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr GetModuleHandle(string lpModuleName);
[DllImport("Kernel32.dll", SetLastError = true, ExactSpelling = true)]
public static extern Int32 WaitForSingleObject(IntPtr handle, Int32 milliseconds);
}
}
P.S I'll add pictures if this wall of text is too boring to read.