26 October, 2016

Trampolines for hooking

Here I would like to show all variants of trampolines which I know.

32-bits Intel architecture (x86):

; 5 code bytes
; relative addressing
; no registers modification
; EIP+78563412h == 0019fa9ah+78563412h == 78702each
0019fa95 e912345678 jmp 78702each
0019fa9a
; 6 code bytes
; absolute addressing
; no registers modification
0019fa95 6812345678 push 78563412h
0019fa9a c3         ret
0019fa9b
; 8 code bytes
; absolute addressing
; EAX value lost
0019fa95 c7c012345678 mov eax,78563412h
0019fa9b ffe0         jmp eax
0019fa9d
; 6 code bytes + 4 data bytes
; absolute addressing
; no registers modification
; data in execution code
; absolute data addressing
0019fa95 ff259bfa1900 jmp dword ptr ds:[19FA9Bh]
0019fa9b 12345678     dd  78563412h
0019fa9f

64-bits AMD architecture (amd64 / x86_64 / x64):

; 14 code bytes
; absolute addressing
; no registers modification
00000000`0014f605 6812345678       push 78563412h
00000000`0014f60a c74424049abcdef0 mov  dword ptr [rsp+4],0F0DEBC9Ah 
00000000`0014f612 c3               ret
00000000`0014f613
; 6 code bytes
; absolute addressing in lower 4Gb
; no registers modification
00000000`0014f605 6812345678 push 78563412h
00000000`0014f60a c3         ret
00000000`0014f60b
; 12 code bytes
; absolute addressing
; change RAX (return value register)
00000000`0014f605 48b8123456789abcdef0 mov  rax,0F0DEBC9A78563412h
00000000`0014f60f ffe0                 jmp  rax
00000000`0014f611
; 13 code bytes
; absolute addressing
; change R11 (temporary register)
00000000`0014f605 49bb123456789abcdef0 mov r11,0F0DEBC9A78563412h
00000000`0014f60f 41ffe3               jmp r11
00000000`0014f612
; 6 code bytes + 8 data bytes in range RIP±2Gb
; absolute addressing
; no registers modification
; data in execution code
; relative data addressing
; RIP+00000000h == 00000000`0014f60bh+00000000h == 00000000`0014f60bh
00000000`0014f605 ff2500000000     jmp qword ptr [00000000`0014f60bh]
00000000`0014f60b 123456789abcdef0 dq  0F0DEBC9A78563412h
00000000`0014f613
; 5 code bytes
; relative addressing RIP±2Gb
; no registers modification
; EIP+78563412h == 00000000`0014f60ah+78563412h == 00000000`786b2a1ch
00000000`0014f605 e912345678 jmp 00000000`786b2a1ch
00000000`0014f60a

P.S. Please let me know if you have new variant.

09 July, 2016

Solve the "no GUID has been associated with this object" compiler error for __uuidof in templates instantinations

As you know WinRT has C++ interfaces ABI::Windows::Foundation::Collections::IIterable and ABI::Windows::Foundation::Collections::IIterable to make iteration in collections universal. This is the very good idea, but you got interfaces with templates: (see windows.foundation.collections.h):

namespace ABI {
namespace Windows {
namespace Foundation {
namespace Collections { 

    template <class T> 
    struct IIterator 
        : IIterator_impl<T>
        , detail::not_yet_specialized<IIterator<T>>
    {
    };

    template <class T> 
    struct IIterable
        : IIterable_impl<T>
        , detail::not_yet_specialized<IIterable<T>>
    {
    };

    template <class T, bool isStruct>
    struct IIterator_impl : IInspectable
    {
    private:
        typedef typename Windows::Foundation::Internal::GetAbiType<T>::type     T_abi;
        typedef typename Windows::Foundation::Internal::GetLogicalType<T>::type T_logical;
    public:
        typedef T                                                               T_complex;

        virtual /* propget */ HRESULT STDMETHODCALLTYPE get_Current(_Out_ T_abi *current) = 0;
        virtual /* propget */ HRESULT STDMETHODCALLTYPE get_HasCurrent(_Out_ boolean *hasCurrent) = 0;
        virtual HRESULT STDMETHODCALLTYPE MoveNext(_Out_ boolean *hasCurrent) = 0;
        virtual HRESULT STDMETHODCALLTYPE GetMany(_In_ unsigned capacity, _Out_writes_to_(capacity,*actual) T_abi *value, _Out_ unsigned *actual) = 0;
    };

    template <class T>
    struct IIterable_impl : IInspectable
    {
    private:
        typedef typename Windows::Foundation::Internal::GetAbiType<T>::type     T_abi;
        typedef typename Windows::Foundation::Internal::GetLogicalType<T>::type T_logical;
    public:
         typedef T                                                               T_complex;

        virtual HRESULT STDMETHODCALLTYPE First(_Outptr_result_maybenull_ IIterator<T_logical> **first) = 0;
    };

}}}}

18 September, 2015

How to load strong named assembly from the location out of application base directory to new application domain

I found the only one decision: dynamically generate the configuration file in temporary folder:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="YYY" culture="" publicKeyToken="0123456789012345" />
        <codeBase version="K.L.M.N" href="file:///X:/XXX/YYY.DLL" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="ZZZ" culture="" publicKeyToken="1234567890123456" />
        <codeBase version="A.B.C.D" href="file:///X:/XXX/ZZZ.DLL" />
      </dependentAssembly>
    </assemblyBinding>
  </runtime>
</configuration>
And set it to AppDomainSetup.ConfigurationFile:
var appDomain = AppDomain.CreateDomain("MyDomain", null, new AppDomainSetup
  {
    ConfigurationFile = configFile
  });

07 September, 2014

Powershell script to close mercurial branches older then 60 days

GitHub link
# Close old branches for Mercurial
# Copyright (C) 2014  Mikhail Pilin
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

if ($PSVersionTable.PSVersion.Major -lt 3) {
  throw "PS Version $($PSVersionTable.PSVersion) is below 3.0."
}

Set-StrictMode -Version Latest
$ErrorActionPreference = [System.Management.Automation.ActionPreference]::Stop
$script:VerbosePreference = "Continue"

$encoding = "cp866"
[System.TimeSpan]$alive = [System.TimeSpan]::FromDays(60)
[System.DateTime]$now = [System.DateTime]::Now

[System.Object]$current = & hg parent --encoding $encoding -T "{node} {branch}" | ForEach-Object {
    $result = $_ | Select-Object -Property node, name
    $parts = $_.Split(' ', 2)
    
    $result.node = $parts[0]
    $result.name = $parts[1]
    $result
  } | Select-Object

Write-Host "Current branch: " -nonewline
Write-Host -foregroundcolor gray $current.name

[System.Object[]]$branches = @(& hg head --encoding $encoding -T "{date(date,'%Y%m%d%H%M%S')} {node} {branch}\n" | ForEach-Object {
    $result = $_ | Select-Object -Property date, node, name
    $parts = $_.Split(' ', 3)

    [System.DateTime]$result.date = [System.DateTime]::ParseExact($parts[0], "yyyyMMddHHmmss", [System.Globalization.CultureInfo]::InvariantCulture)
    $result.node = $parts[1]
    $result.name = $parts[2]
    $result
  } | Where-Object { $now - $_.date -gt $alive } | Sort-Object -property date)

function EscapeBranchName
{
  Param([System.String]$name)
  $name.Replace('"', '\"')
}

if ($branches.Length -eq 0) { Write-Host "No old branches were detected" } else {
  Write-Host "Closing $($branches.Length) old branches:"

  $branches | ForEach-Object {
      Write-Host "[$([System.String]::Format("{0:%d}", $now - $_.date)) days] " -nonewline
      Write-Host -foregroundcolor gray $_.name

      & hg debugsetparent $_.node | Out-Null
      if ($LastExitCode -ne 0) { Write-Warning "Failed to set node (exit code $LastExitCode)." } else {
        & hg branch $(EscapeBranchName $_.name) | Out-Null
        if ($LastExitCode -ne 0) { Write-Warning "Failed to set branch (exit code $LastExitCode)." } else {
          & hg commit --close-branch -X * -m $("The branch was not used for {0:%d} days and closed automatically." -f ($now - $_.date)) | Out-Null
          if ($LastExitCode -ne 0) { Write-Warning "Failed to commit (exit code $LastExitCode)." }
        }
      }
    }

  Write-Host "Restore current branch: " -nonewline
  Write-Host -foregroundcolor gray $current.name

  & hg debugsetparent $current.node | Out-Null
  if ($LastExitCode -ne 0) { Write-Warning "Failed to set node (exit code $LastExitCode)." } else {
    & hg branch $(EscapeBranchName $current.name) | Out-Null
    if ($LastExitCode -ne 0) { Write-Warning "Failed to set branch (exit code $LastExitCode)." }
  }
}

02 March, 2014

Decoding the parameters of a thrown C++ exception (0xE06D7363)

I have a lot questions after reading the post about decoding structural exception 0xE06D7363 from "The Old New Thing". I like computer magic like that: take address from here add the constant two and half time and you get it. However, this magic don't help to understand how it really works and what happened if I do that. So, following code from CRT kill all magic.

06 November, 2013

How to install .NET Framework 1.1 on Windows 8.1

After update from Windows 8.0 to Windows 8.1 I found that .NET Framework 1.1 was unexpectedly disappeared. Here I give you the tested way to return it back:

  • Download .NET Framework Cleanup Tool (product guide here) from following locations: here or here
  • Unzip and run following commands:
    cleanup_tool.exe /q:a /c:"cleanup.exe /p .NET Framework 1.0"
    cleanup_tool.exe /q:a /c:"cleanup.exe /p .NET Framework 1.1"
    
  • Following instructions were taken from here:
    • Create a new folder named DotNet in C:\ drive. (The path i used was C:\DotNet)
    • Download Microsoft .NET Framework 1.1 Redistributable Package (dotnetfx.exe). Make sure the setup file is saved as dotnetfx.exe.
    • Download Microsoft .NET Framework 1.1 Service Pack 1 (NDP1.1sp1-KB867460-X86.exe). Rename the file to dotnetfxsp1.exe.
    • Copy both installation files into the same directory (i.e. C:\DotNet),.
    • Open Command Prompt as Administrator.
    • Change to the directory where the two installation files are stored, ie C:\DotNet.
    • Run the following commands one by one:
      dotnetfx.exe /c:"msiexec.exe /a netfx.msi TARGETDIR=C:\DotNet"
      dotnetfxsp1.exe /Xp:C:\DotNet\netfxsp.msp
      msiexec.exe /a c:\DotNet\netfx.msi /p c:\DotNet\netfxsp.msp
      
    • Install Microsoft .Net Framework 1.1 with slipstreamed Service Pack 1 by running netfx.msi from the working folder.

Good luck!

07 June, 2013

Tricky macro to add file name and line number in C++ operator new

Header file:

#if defined(_DEBUG)
  #define _CRTDBG_MAP_ALLOC

  #include <crtdbg.h>

  extern __declspec(thread) char const * t_File;
  extern __declspec(thread) int t_Line;

  inline void * __CRTDECL operator new  (size_t const size) { return ::operator new  (size, _NORMAL_BLOCK, t_File, t_Line); }
  inline void * __CRTDECL operator new[](size_t const size) { return ::operator new[](size, _NORMAL_BLOCK, t_File, t_Line); }

  #define new (t_File = __FILE__, t_Line = __LINE__, false) ? nullptr : new
#endif
Source file:
#if defined(_DEBUG)
  __declspec(thread) char const * t_File = "???";
  __declspec(thread) int t_Line = 0;
#endif

This macro doesn't work with direct operator call like operator new(...) in code.

P.S. This macro tested only on Visual Studio 2012

06 June, 2013

How to enable ARM support for desktop application in Visual Studio 2012?

Just add following in your .vcxproj file, somewhere at the beginning:

<PropertyGroup>
  <WindowsSDKDesktopARMSupport>true</WindowsSDKDesktopARMSupport>
</PropertyGroup>

P.S. Surely Windows SDK for Windows 8 has to be installed.