Tuesday, September 27, 2011

Run Heroes of Might and Magic III on Android

This old classic PC game – Heroes of Might & Magic III has brought to Android platform by an open source project VCMI, its development team has done a remarkable work to make it running on an Android tablet.

How to install:

1. Download VCMI from the Android market from https://market.android.com/details?id=eu.vcmi&hl=en

2. Run VCMI once, it will create the directories on your /sdcard/app-data

3. Install a full version of Heroes of Might & Magic ||| on your PC, you can buy it from http://www.gog.com/en/gamecard/heroes_of_might_and_magic_3_complete_edition , currently VCMI only support english version, you can find out more in their wiki http://wiki.vcmi.eu/index.php?title=Main_Page

4. After install the heroes of might & magic III you will need to install WOG, download from here http://www.maps4heroes.com/heroes3/files/allinone_385f.zip

5. Unzip WOG(files with install.exe) to Heroes of Might & Magic |||/UPDATE/ folder & run install.exe, this installation will take a while, please be patient.

6. Connect your tablet to your PC with USB cable & copy all files under your installation of Heroes of Might & Magic |||/* to /sdcard/app-data/eu.vcmi/

7. Run VCMI again after copy is finished & enjoy your game 🙂

NOTE: Currently only hotseat mode is enabled, you need to select multiple player -> hotseat as the AI engine is not completed yet
You can moreover download latest build of VCMI project from http://forum.vcmi.eu/portal.php

 

 

 

 

Friday, September 16, 2011

Hook ntdll!NtDeviceIoControlFile to capture network packets

unit uNtDeviceIoControl;interfaceuses  SysUtils, Windows;const  AFD_RECV = $12017;  AFD_SEND = $1201f;  HTTP_GET: AnsiString = 'GET ';  HTTP_POST: AnsiString = 'POST ';  HTTP_RESPONSE: AnsiString = 'HTTP';type  NTSTATUS = DWORD;  PVOID = Pointer;  _AFD_WSABUF = record    len: DWORD;    buf: PAnsiChar;  end;  TAFD_WSABUF = _AFD_WSABUF;  PAFD_WSABUF = ^TAFD_WSABUF;  _AFD_INFO = record    BufferArray: PAFD_WSABUF;    BufferCount: DWORD;    AfdFlags: DWORD;    TdiFlags: DWORD;  end;  TAFD_INFO = _AFD_INFO;  PAFD_INFO = ^TAFD_INFO;  _IO_STATUS_BLOCK = record    //union {    Status: NTSTATUS;    //    PVOID Pointer;    //}    Information: ULONG_PTR;  end;  IO_STATUS_BLOCK = _IO_STATUS_BLOCK;  PIO_STATUS_BLOCK = ^IO_STATUS_BLOCK;  TIoStatusBlock = IO_STATUS_BLOCK;  PIoStatusBlock = ^TIoStatusBlock;  PIO_APC_ROUTINE = procedure(ApcContext: PVOID; IoStatusBlock: PIO_STATUS_BLOCK; Reserved: ULONG); stdcall;  PIMAGE_IMPORT_DESCRIPTOR = ^_IMAGE_IMPORT_DESCRIPTOR;  PImageImportDescriptor = PIMAGE_IMPORT_DESCRIPTOR;  _IMAGE_IMPORT_DESCRIPTOR = packed record    CharacteristicsOrOriginalFirstThunk: DWord;    TimeDateStamp: DWord;    ForwarderChain: DWord;    Name: DWord;    FirstThunk: DWord;  end;  PIMAGE_THUNK_DATA = ^_IMAGE_THUNK_DATA;  PImageThunkData = PIMAGE_THUNK_DATA;  _IMAGE_THUNK_DATA = packed record    case Integer of      0 : (ForwarderString: DWord);      1 : (Function_: DWord);      2 : (Ordinal: DWord);      3 : (AddressOfData: DWord);  end;function NT_SUCCESS(Status: NTSTATUS): BOOL;{$EXTERNALSYM NT_SUCCESS}var  OldNtDeviceIoControl: DWORD;procedure SuperHookDeviceIoControl();implementationfunction NT_SUCCESS(Status: NTSTATUS): BOOL;begin  //Result := Status >= 0;  Result := Status < $80000000;end;//////////////////////////////////////////////////////////////////////////////// LookupSendPacket////// Check Send Packets/// Currently implements filter http requests(GET AND POST)/////////////////////////////////////////////////////////////////////////////function LookupSendPacket(Buffer: Pointer; Len: DWORD): Boolean;begin  Result := False;  // drop small packets  if (Len < 10) then Exit;  // check if it is GET or POST.  if ( CompareMem(Buffer, @HTTP_GET[1], 4)    or CompareMem(Buffer, @HTTP_POST[1], 4) ) then  begin    Result := True;  end;end;//////////////////////////////////////////////////////////////////////////////// LookupRecvPacket////// Check Recv Packets/// Currently implements filter http response packets./////////////////////////////////////////////////////////////////////////////////function LookupRecvPacket(Buffer: Pointer; Len: DWORD): Boolean;begin  Result := False;  if (Len < 10) then Exit;  if ( CompareMem(Buffer, @HTTP_RESPONSE[1], 4) ) then  begin    Result := True;  end;end;{ HOOK functions }//////////////////////////////////////////////////////////////////////////////// The hooked NtDeviceIoControlFile function./// "send" & "recv" functions in ws2_32.dll finally will call functions in mswsock.dll,/// & mswsock.dll will call NtDeviceIoControl to send "send" or "recv" commands to TDI Client driver./// So if we hook it here, we can filter all tcp packets.//////////////////////////////////////////////////////////////////////////////// Compatibility: NT3, NT4, W2K, WXP, 2K3function NewNtDeviceIoControlFile(    FileHandle : THANDLE;    Event : THANDLE;    ApcRoutine : PIO_APC_ROUTINE;    ApcContext : PVOID;    IoStatusBlock : PIO_STATUS_BLOCK;    IoControlCode : ULONG;    InputBuffer : PVOID;    InputBufferLength : ULONG;    OutputBuffer : PVOID;    OutputBufferLength : ULONG  ): NTSTATUS; stdcall;var  AfdInfo: PAFD_INFO;  Buffer: PAnsiChar;  Len: DWORD;begin  // call the original function first.  asm    push  OutputBufferLength    push  OutputBuffer    push  InputBufferLength    push  InputBuffer    push  IoControlCode    push  IoStatusBlock    push  ApcContext    push  ApcRoutine    push  Event    push  FileHandle    call  OldNtDeviceIoControl    mov   Result, eax  end;  // if original function failed  if (Not NT_SUCCESS(Result)) then  begin    Exit;  end;  // check whether it is TCP send or recv.  if (IoControlCode <> AFD_SEND)    & (IoControlCode <> AFD_RECV) then  begin    Exit;  end;  try    // obtain Buffer & Len from InputBuffer    AfdInfo := PAFD_INFO(InputBuffer);    Buffer := AfdInfo.BufferArray.buf;    Len := AfdInfo.BufferArray.len;    case IoControlCode of      AFD_SEND:        if ( LookupSendPacket(Buffer, Len) ) then        begin          // output packet content.          OutputDebugString(PChar(Format('[HTTP Send] Length = %d', [Len])));          OutputDebugString(PChar(Format('%s', [StrPas(Buffer)])));        end;      AFD_RECV:        if ( LookupRecvPacket(Buffer, Len) ) then        begin          // output packet content.          OutputDebugString(PChar(Format('[HTTP Recv] Length = %d', [Len])));          OutputDebugString(PChar(Format('%s', [StrPas(Buffer)])));        end;    end;  except  end;end;////////////////////////////////////////////////////////////////////////////////  Setup hook to Ntdll!NtDeviceIoControlFile in mswsock.dll import table/////////////////////////////////////////////////////////////////////////////procedure SuperHookDeviceIoControl();var  hMod: HMODULE;  pDosHeader: PImageDosHeader;  pNtHeaders: PImageNtHeaders;  ImportDescriptor: PImageImportDescriptor;  ThunkData: PImageThunkData;  dll_name, func_name: PAnsiChar;  iNum: Integer;  lpAddr: Pointer;  myaddr, btw: DWORD;begin  hMod := LoadLibrary('mswsock.dll');  if (hMod = 0) then  begin    OutputDebugString(PChar(Format('LoadLibrary(%s)失败!', ['mswsock.dll'])));    Exit;  end;  // obtain DOS header  pDosHeader := PImageDosHeader(hMod);  if ( pDosHeader^.e_magic <> IMAGE_DOS_SIGNATURE ) then  begin    Exit;  end;  // obtain NT header  pNtHeaders := PImageNtHeaders(hMod + DWORD(pDosHeader^._lfanew));  if ( pNtHeaders^.Signature <> IMAGE_NT_SIGNATURE ) then  begin    Exit;  end;  if (pNtHeaders^.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress = 0)    or (pNtHeaders^.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size = 0) then  begin    Exit;  end;  ImportDescriptor := PImageImportDescriptor(hMod + pNtHeaders^.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);  while (ImportDescriptor^.FirstThunk <> 0) do  begin    dll_name := PAnsiChar(hMod + ImportDescriptor^.Name);    if (StrIComp(dll_name, 'ntdll.dll') <> 0) then    begin      ImportDescriptor := PImageImportDescriptor(DWORD(ImportDescriptor) + SizeOf(_IMAGE_IMPORT_DESCRIPTOR));      Continue;    end;    ThunkData := PImageThunkData(hMod + ImportDescriptor^.CharacteristicsOrOriginalFirstThunk);    iNum := 1;    while (ThunkData^.Function_ <> 0) do    begin      func_name := PAnsiChar(hMod + ThunkData^.AddressOfData + 2);      //OutputDebugString(PChar(Format('[HOOK] find API: %s', [StrPas(func_name)])));      if (StrIComp(func_name , 'NtDeviceIoControlFile') = 0) then      begin        OutputDebugString(PChar(Format('[HOOK] Lock "%s" for HOOK.', [StrPas(func_name)])));        //        // if found NtDeviceIoControlFile, save original function address.        // then setup our hook function address.        //        // ID	 RVA	 Offset  Name        //   9A  D8E3  CCE3      NtDeviceIoControlFile        myaddr := DWORD(@NewNtDeviceIoControlFile);        lpAddr := Pointer(hMod + ImportDescriptor^.FirstThunk + DWORD(iNum-1)*4);        OldNtDeviceIoControl := PDWORD(lpAddr)^;        OutputDebugString(PChar(Format('[HOOK] Base=%0.8X, Thunk=%0.8X, ID=%X', [hMod, ImportDescriptor^.FirstThunk, iNum-1])));        OutputDebugString(PChar(Format('[HOOK] Orign[0x%0.8X]=0x%0.8X, new Addr=0x%0.8X', [DWORD(lpAddr), PDWORD(lpAddr)^, myaddr])));        WriteProcessMemory(GetCurrentProcess(), lpAddr, @myaddr, 4, btw);        Exit;      end;      Inc(iNum);      ThunkData := PImageThunkData(DWORD(ThunkData) + SizeOf(_IMAGE_THUNK_DATA));    end;    Inc(ImportDescriptor);  end;end;end.

API Hook Engine for Delphi

This is an Windows NT API hook engine for Delphi, built with Delphi XE. I think it can be compiled under other Delphi versions.

Archives:
libHttpHook.7z: This is the hook engine & demo dll, it hooked winsock 2.0 send & recv funcs. If you inject the dll into a process, you can use any debug viewer to see its network packets.
DllInjector.7z: This is a simple dll injector. Use it to test libHttpHook.dll.

Wish you like!

Download:
DllInjector.7z: Mirror 1
libHttpHook.7z: Mirror 1
Unpack password: www.x-note.co.uk

Some comments were written in Chinese. If you received any problem, please contact me on “xmacmail [at] gmail.com”