Solved

C# translation

Posted on 2004-04-09
12
922 Views
Last Modified: 2007-12-19
What would the C# equiv be of this code?:

bool Hook(const TCHAR * module, const TCHAR * proc, unsigned & syscall_id, BYTE * & pProc, const void * pNewProc)
{
    HINSTANCE hMod = GetModuleHandle(module);

    pProc = (BYTE *) GetProcAddress(hMod, proc);

    if ( pProc[0] == 0xB8 )
    {
        syscall_id = * (unsigned *) (pProc + 1);

        DWORD flOldProtect;

        VirtualProtect(pProc, 5, PAGE_EXECUTE_READWRITE, & flOldProtect);

        pProc[0] = 0xE9;
        * (unsigned *) (pProc+1) = (unsigned)pNewProc - (unsigned) (pProc+5);

        pProc += 5;

        return true;
    }
    else
        return false;
}
0
Comment
Question by:rossryan
  • 7
  • 5
12 Comments
 
LVL 48

Expert Comment

by:AlexFM
ID: 10789712
rossryan, after reading all stuff you want to translate I think you need to implement it in mixed C++ project.
First, it's impossible to translate C++ function to C#. It is possible to call API in C#, but translating the whole C++ function...

bool Hook(const TCHAR * module, const TCHAR * proc, unsigned & syscall_id, BYTE * & pProc, const void * pNewProc)

It's impossible to translate this to C#. Possibly pNewProc is C# delegate. TCHAR* is String. But converting all this stuff to C# is not equal to converting of single API calls.

I think you have wotking C++ project or class which makes some paint hook. The best thing you can do this is to write managed C++ wrapper for it and use this wrapper in C# code.
0
 

Author Comment

by:rossryan
ID: 10794425
Any ideas how to do that? I've been thinking about stripping out the class, compiling it as a dll, and using static extern to grab the procedures...
0
 
LVL 48

Expert Comment

by:AlexFM
ID: 10795842
Generally, there are 2 ways:
1) Make unmanaged Dll which internally uses C++ class and exposes C-style interface (API) available in C#
2) Make mixed managed/unmanaged C++ Dll which uses internally C++ class and exposes pure managed interface for C# client.

I think first you should think about desired interface for your C# client: set of API or managed class. What information do you need from server?

Suppose you have the following C++ class:

class A
{
public:
     A(int n){ m_n = n};
     ~A();
     int Get(return m_n);
private:
     int m_n;
};

API interface for C# client may look like this:

void* CreateA(int n)
{
    A* pA = new A(n);
    return (void*) pA;
}

void DeleteA(void* p)
{
    A* pA = (A*)p;
    delete p;
}

int GetA(void* p)
{
    A* pA = (A*)p;
    return pA->n;
}

API wrapper contains Create and Delete function and function for each public class member. Member wrapper always gets pointer to class instance as it's first parameter. In C# this pointer is kepr in IntPtr variable.
0
 

Author Comment

by:rossryan
ID: 10795986
Do you have a minute to help me get this working (wrappers are new to me). For ease of use, I'll give you all the files below.


// PaintHookWrapper.h
//This is the wrapper class.
#pragma once
#include "PaintHook.h"
#pragma managed
#using <mscorlib.dll>
using namespace System;


namespace PaintHookWrapper
{
      public __gc class PaintHookEx : public ICloneable
      {
      public:
            PaintHookEx();

            virtual Object* Clone()
            {            
            PaintHookEx* mHook = new PaintHookEx();      
            *(mHook->m_pCPaintHook) = *m_pCPaintHook;  
            return mHook;
            }

            void SubClass(HWND hWnd);
            bool Within_WM_PRINT();

      private:
            CPaintHook __nogc* m_pCPaintHook;
      };

      PaintHookEx::PaintHookEx()
      {
            m_pCPaintHook = new CPaintHook();
      }
      void PaintHookEx::SubClass(HWND hWnd)
      {
            m_pCPaintHook->SubClass(hWnd);

      }
      bool PaintHookEx::Within_WM_PRINT()
      {
            return m_pCPaintHook->Within_WM_PRINT();
      }

}

// Copyright (C) 2000 by Feng Yuan (www.fengyuan.com)
// Feng Yuan's class (Paint Hook) which I am trying to access from c#.
//PaintHook.h

// Windows Header Files:
#include <windows.h>

// C RunTime Header Files
#include <stdlib.h>
#include <malloc.h>
#include <memory.h>
#include <tchar.h>
class CPaintHook
{
    BYTE      m_thunk[9];
    WNDPROC   m_OldWndProc;
    HDC       m_hDC;

    static HDC  WINAPI MyBeginPaint(HWND hWnd, LPPAINTSTRUCT lpPaint);
    static BOOL WINAPI MyEndPaint(HWND hWnd, LPPAINTSTRUCT lpPaint);

    virtual LRESULT WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
      
public:
   
    bool Within_WM_PRINT(void) const
    {  
        if ( IsBadWritePtr((void *) this, sizeof(CPaintHook)) )
            return false;

        if ( (m_thunk[0]==0xB9) && ((* (unsigned *) (m_thunk+5))==0x20FF018B) )
            return m_hDC !=0;
        else
            return false;
    }    
   
     CPaintHook(void);

    void SubClass(HWND hWnd);
};

// Copyright (C) 2000 by Feng Yuan (www.fengyuan.com)
//PaintHook.cpp file
#include "stdafx.h"
#include <assert.h>
// Windows Header Files:


#include "PaintHook.h"

bool Hook(const TCHAR * module, const TCHAR * proc, unsigned & syscall_id, BYTE * & pProc, const void * pNewProc)
{
    HINSTANCE hMod = GetModuleHandle(module);

    pProc = (BYTE *) GetProcAddress(hMod, proc);

    if ( pProc[0] == 0xB8 )
    {
        syscall_id = * (unsigned *) (pProc + 1);

        DWORD flOldProtect;

        VirtualProtect(pProc, 5, PAGE_EXECUTE_READWRITE, & flOldProtect);

        pProc[0] = 0xE9;
        * (unsigned *) (pProc+1) = (unsigned)pNewProc - (unsigned) (pProc+5);

        pProc += 5;

        return true;
    }
    else
        return false;
}


static unsigned syscall_BeginPaint = 0;
static BYTE *   pBeginPaint        = NULL;

static unsigned syscall_EndPaint   = 0;
static BYTE *   pEndPaint          = NULL;


LRESULT CPaintHook::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    //assert(m_OldWndProc);

    if ( uMsg==WM_PRINTCLIENT )
    {
        m_hDC = (HDC) wParam;
        uMsg  = WM_PAINT;
    }
       
    LRESULT hRslt = CallWindowProc(m_OldWndProc, hWnd, uMsg, wParam, lParam);

    m_hDC = NULL;

    return hRslt;
}
      

HDC WINAPI CPaintHook::MyBeginPaint(HWND hWnd, LPPAINTSTRUCT lpPaint)
{
    const CPaintHook * pThis = (CPaintHook *) GetWindowLong(hWnd, GWL_WNDPROC);
   
    pThis = (const CPaintHook *) ( (unsigned) pThis - (unsigned) & pThis->m_thunk[0] + (unsigned) pThis );
   
    if ( pThis->Within_WM_PRINT() )
    {
        memset(lpPaint, 0, sizeof(PAINTSTRUCT));

        lpPaint->hdc = pThis->m_hDC;
       
        GetClientRect(hWnd, & lpPaint->rcPaint);
       
        return pThis->m_hDC;
    }
    else
    {
        __asm   mov     eax, syscall_BeginPaint
        __asm   push    lpPaint
        __asm   push    hWnd
        __asm   call    pBeginPaint
    }
}


BOOL WINAPI CPaintHook::MyEndPaint(HWND hWnd, LPPAINTSTRUCT lpPaint)
{
    const CPaintHook * pThis = (CPaintHook *) GetWindowLong(hWnd, GWL_WNDPROC);
   
    pThis = (const CPaintHook *) ( (unsigned) pThis - (unsigned) & pThis->m_thunk[0] + (unsigned) pThis );
   
    if ( pThis->Within_WM_PRINT() )
        return TRUE;
    else
    {
        __asm   mov     eax, syscall_EndPaint
        __asm   push    lpPaint
        __asm   push    hWnd
        __asm   call    pEndPaint
    }
}

CPaintHook::CPaintHook()
{
    static bool s_hooked = false;

    if ( ! s_hooked )
    {
        Hook("USER32.DLL", "BeginPaint", syscall_BeginPaint, pBeginPaint, MyBeginPaint);
        Hook("USER32.DLL", "EndPaint",   syscall_EndPaint,   pEndPaint,   MyEndPaint);

        s_hooked = true;
    }

    m_thunk[0]              = 0xB9;               // mov ecx,
    *((DWORD *)(m_thunk+1)) = (DWORD) this;  //          this
      *((DWORD *)(m_thunk+5)) = 0x20FF018B;    // mov eax, [ecx]

    m_OldWndProc = NULL;
    m_hDC        = NULL;
}


void CPaintHook::SubClass(HWND hWnd)
{            
    m_OldWndProc = (WNDPROC) GetWindowLong(hWnd, GWL_WNDPROC);
    SetWindowLong(hWnd, GWL_WNDPROC, (LONG) ((void *) m_thunk));
}



Basically, I need the functionality provided by Feng's code, but I do not know how to properly wrap it. I have attempted above, but two things: 1.) I keep getting a linker error, and 2.) it looks like he hasn't implemented a destructor (no worries, I'll get around to it later). Any help would be greatly appreciated.
0
 

Author Comment

by:rossryan
ID: 10795992
Oh yeah, all code is in a .NET Managed class library (VS.NET 2003).
0
 
LVL 48

Expert Comment

by:AlexFM
ID: 10796044
If you want API wrapper, create unmanaged Dll (in my case it is called Sample):
File - New - Project - Visual C++ Projects - Win32 - Win32 Project. In Application Settings dialog select Dll, check Export Symbols ( to have some sample code). Press Finish.
Open Sample.h and Sample.cpp files. Remove CSample class and nSample variable from both files. fnSample function should be removed also, but instead of it you need to add API wrapper functions to Dll. These functions should be used by C# client using PInvoke.
Add PaintHook.h and PaintHook.cpp files to the project. Include PaintHook.h to Sample.cpp.

Add the following functions prototypes to Sample.h:

SAMPLE_API void* CreatePaintHook();
SAMPLE_API void DeletePaintHook(void* p);
SAMPLE_API void SubClass(void* p, HWND hWnd);
SAMPLE_API bool Within_WM_PRINT(void* p);

Add function implementations to Sample.cpp:

SAMPLE_API void* CreatePaintHook()
{
    CPaintHook* p = new CPaintHook();
    return (void*)p;
}

SAMPLE_API void DeletePaintHook(void* p)   // you still need this even if CPaintHook doesn't have destructor
{
    CPaintHook* pHook = (CPaintHook*)p;
    delete pHook;
}

SAMPLE_API void SubClass(void* p, HWND hWnd)
{
    CPaintHook* pHook = (CPaintHook*)p;
    pHook->SubClass(hWnd);
}

SAMPLE_API bool Within_WM_PRINT(void* p)
{
    CPaintHook* pHook = (CPaintHook*)p;
    return pHook->Within_WM_PRINT();
}

In C# client call CreatePaintHook and keep result in IntPtr variable. After this call other function always passing as first parameter this variable. To release C++ instance call DeletePaintHook.

Your problem is similar to the problem of C programmer who wants to use C++ class. It is solved by the same way.
0
Top 6 Sources for Identifying Threat Actor TTPs

Understanding your enemy is essential. These six sources will help you identify the most popular threat actor tactics, techniques, and procedures (TTPs).

 

Author Comment

by:rossryan
ID: 10799461
Hmm. Created the project with the files below, compiles ok. I copied the dll to my other project folder, but when I go to add reference, I get a not valid assembly or COM component. Here are the files below:

//Sample.h
// The following ifdef block is the standard way of creating macros which make exporting
// from a DLL simpler. All files within this DLL are compiled with the SAMPLE_EXPORTS
// symbol defined on the command line. this symbol should not be defined on any project
// that uses this DLL. This way any other project whose source files include this file see
// SAMPLE_API functions as being imported from a DLL, whereas this DLL sees symbols
// defined with this macro as being exported.
#ifdef SAMPLE_EXPORTS
#define SAMPLE_API __declspec(dllexport)
#else
#define SAMPLE_API __declspec(dllimport)
#endif

// This class is exported from the Sample.dll


SAMPLE_API void* CreatePaintHook();
SAMPLE_API void DeletePaintHook(void* p);
SAMPLE_API void SubClass(void* p, HWND hWnd);
SAMPLE_API bool Within_WM_PRINT(void* p);


//SAMPLE_API int fnSample(void);





// Sample.cpp : Defines the entry point for the DLL application.
//

#include "stdafx.h"
#include "Sample.h"
#include "PaintHook.h"
BOOL APIENTRY DllMain( HANDLE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                               )
{
      switch (ul_reason_for_call)
      {
      case DLL_PROCESS_ATTACH:
      case DLL_THREAD_ATTACH:
      case DLL_THREAD_DETACH:
      case DLL_PROCESS_DETACH:
            break;
      }
    return TRUE;
}

// This is an example of an exported variable


/*
// This is an example of an exported function.
SAMPLE_API int fnSample(void)
{
      return 42;
}
*/

// This is the constructor of a class that has been exported.
// see Sample.h for the class definition


SAMPLE_API void* CreatePaintHook()
{
    CPaintHook* p = new CPaintHook();
    return (void*)p;
}

SAMPLE_API void DeletePaintHook(void* p)   // you still need this even if CPaintHook doesn't have destructor
{
    CPaintHook* pHook = (CPaintHook*)p;
    delete pHook;
}

SAMPLE_API void SubClass(void* p, HWND hWnd)
{
    CPaintHook* pHook = (CPaintHook*)p;
    pHook->SubClass(hWnd);
}

SAMPLE_API bool Within_WM_PRINT(void* p)
{
    CPaintHook* pHook = (CPaintHook*)p;
    return pHook->Within_WM_PRINT();
}



//PaintHook.h
// Copyright (C) 2000 by Feng Yuan (www.fengyuan.com)


//#include "SwitchClass.h"
class CPaintHook
{
    BYTE      m_thunk[9];
    WNDPROC   m_OldWndProc;
    HDC       m_hDC;

    static HDC  WINAPI MyBeginPaint(HWND hWnd, LPPAINTSTRUCT lpPaint);
    static BOOL WINAPI MyEndPaint(HWND hWnd, LPPAINTSTRUCT lpPaint);

    virtual LRESULT WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
      
public:
   
    bool Within_WM_PRINT(void) const
    {  
        if ( IsBadWritePtr((void *) this, sizeof(CPaintHook)) )
            return false;

        if ( (m_thunk[0]==0xB9) && ((* (unsigned *) (m_thunk+5))==0x20FF018B) )
            return m_hDC !=0;
        else
            return false;
    }    
   
    CPaintHook(void);

    void SubClass(HWND hWnd);
};


//PaintHook.cpp
// Copyright (C) 2000 by Feng Yuan (www.fengyuan.com)

#include "stdafx.h"
#include <assert.h>

#include "PaintHook.h"

bool Hook(const TCHAR * module, const TCHAR * proc, unsigned & syscall_id, BYTE * & pProc, const void * pNewProc)
{
    HINSTANCE hMod = GetModuleHandle(module);

    pProc = (BYTE *) GetProcAddress(hMod, proc);

    if ( pProc[0] == 0xB8 )
    {
        syscall_id = * (unsigned *) (pProc + 1);

        DWORD flOldProtect;

        VirtualProtect(pProc, 5, PAGE_EXECUTE_READWRITE, & flOldProtect);

        pProc[0] = 0xE9;
        * (unsigned *) (pProc+1) = (unsigned)pNewProc - (unsigned) (pProc+5);

        pProc += 5;

        return true;
    }
    else
        return false;
}


static unsigned syscall_BeginPaint = 0;
static BYTE *   pBeginPaint        = NULL;

static unsigned syscall_EndPaint   = 0;
static BYTE *   pEndPaint          = NULL;


LRESULT CPaintHook::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    assert(m_OldWndProc);

    if ( uMsg==WM_PRINTCLIENT )
    {
        m_hDC = (HDC) wParam;
        uMsg  = WM_PAINT;
    }
       
    LRESULT hRslt = CallWindowProc(m_OldWndProc, hWnd, uMsg, wParam, lParam);

    m_hDC = NULL;

    return hRslt;
}
      

HDC WINAPI CPaintHook::MyBeginPaint(HWND hWnd, LPPAINTSTRUCT lpPaint)
{
    const CPaintHook * pThis = (CPaintHook *) GetWindowLong(hWnd, GWL_WNDPROC);
   
    pThis = (const CPaintHook *) ( (unsigned) pThis - (unsigned) & pThis->m_thunk[0] + (unsigned) pThis );
   
    if ( pThis->Within_WM_PRINT() )
    {
        memset(lpPaint, 0, sizeof(PAINTSTRUCT));

        lpPaint->hdc = pThis->m_hDC;
       
        GetClientRect(hWnd, & lpPaint->rcPaint);
       
        return pThis->m_hDC;
    }
    else
    {
        __asm   mov     eax, syscall_BeginPaint
        __asm   push    lpPaint
        __asm   push    hWnd
        __asm   call    pBeginPaint
    }
}


BOOL WINAPI CPaintHook::MyEndPaint(HWND hWnd, LPPAINTSTRUCT lpPaint)
{
    const CPaintHook * pThis = (CPaintHook *) GetWindowLong(hWnd, GWL_WNDPROC);
   
    pThis = (const CPaintHook *) ( (unsigned) pThis - (unsigned) & pThis->m_thunk[0] + (unsigned) pThis );
   
    if ( pThis->Within_WM_PRINT() )
        return TRUE;
    else
    {
        __asm   mov     eax, syscall_EndPaint
        __asm   push    lpPaint
        __asm   push    hWnd
        __asm   call    pEndPaint
    }
}

CPaintHook::CPaintHook()
{
    static bool s_hooked = false;

    if ( ! s_hooked )
    {
        Hook("USER32.DLL", "BeginPaint", syscall_BeginPaint, pBeginPaint, MyBeginPaint);
        Hook("USER32.DLL", "EndPaint",   syscall_EndPaint,   pEndPaint,   MyEndPaint);

        s_hooked = true;
    }

    m_thunk[0]              = 0xB9;               // mov ecx,
    *((DWORD *)(m_thunk+1)) = (DWORD) this;  //          this
      *((DWORD *)(m_thunk+5)) = 0x20FF018B;    // mov eax, [ecx]

    m_OldWndProc = NULL;
    m_hDC        = NULL;
}


void CPaintHook::SubClass(HWND hWnd)
{            
    m_OldWndProc = (WNDPROC) GetWindowLong(hWnd, GWL_WNDPROC);
    SetWindowLong(hWnd, GWL_WNDPROC, (LONG) ((void *) m_thunk));
}


0
 

Author Comment

by:rossryan
ID: 10799752
Any thoughts on why a C# project would not be able to reference this project?
0
 

Author Comment

by:rossryan
ID: 10799802
I guess what I do not understand is how an unmanaged dll can be accessed by managed code...
0
 
LVL 48

Accepted Solution

by:
AlexFM earned 500 total points
ID: 10799961
You don't need to reference this Dll, use PInvoke to call it's functions:

       [DllImport ("Sample.dll")]
       public static extern IntPtr CreatePaintHook();

       [DllImport ("Sample.dll")]
       public static extern void DeletePaintHook(IntPtr p);

       [DllImport ("Sample.dll")]
       public static extern void SubClass(IntPtr p, IntPtr hWnd);

       [DllImport ("Sample.dll")]
       public static extern int Within_WM_PRINT(IntPtr p);

By the way, it's beter to replace return code of Within_WM_PRINT to int, since bool type may be DWORD, BYTE etc. and int type is more "predictable".

Unmanaged non-COM Dll may be accessed from managed code using PInvoke (API), classes from this Dll cannot be accessed from C#. This is a reason of writing C-style interface around C++ class.
0
 

Author Comment

by:rossryan
ID: 10799990
Very nice, and please kill me for forgetting PInvoke. I literally have lines of it:

[DllImport("GDI32.dll")]
            public static extern bool BitBlt(int hdcDest,int nXDest,int nYDest,
                  int nWidth,int nHeight,int hdcSrc,
                  int nXSrc,int nYSrc,int dwRop);
            [DllImport("GDI32.dll")]
            public static extern bool BitBlt(IntPtr hdcDest,int nXDest,int nYDest,
                  int nWidth,int nHeight,IntPtr hdcSrc,
                  int nXSrc,int nYSrc,int dwRop);
            [DllImport("GDI32.dll")]
            public static extern int CreateCompatibleBitmap(int hdc,int nWidth,
                  int nHeight);
            [DllImport("GDI32.dll")]
            public static extern IntPtr CreateCompatibleBitmap(IntPtr hdc,int nWidth,
                  int nHeight);
            [DllImport("GDI32.dll")]
            public static extern int CreateCompatibleDC(int hdc);
            [DllImport("GDI32.dll")]
            public static extern IntPtr CreateCompatibleDC(IntPtr hdc);
            [DllImport("GDI32.dll")]
            public static extern bool DeleteDC(int hdc);

Anyways, you got the points, and if you make it to the other questions (C# Translations[i]) before I finish stress testing some features, I'll give you those points as well. This class is immensely useful for some operations I need.

Thanks,
Ryan
0
 
LVL 48

Expert Comment

by:AlexFM
ID: 10800046
Hi rossryan, nice to see that I can help.
EE rules doesn't allow to experts to get more than 500 points for one question. However, in some extraordinary cases it is possible to get additional 500 points. Since I provided two different solutions to your "C# translation" questions, I allow to myself to add notes to two more questions from this series. You can accept them as an answer if you think I deserve this. Thanks.
0

Featured Post

What Security Threats Are You Missing?

Enhance your security with threat intelligence from the web. Get trending threat insights on hackers, exploits, and suspicious IP addresses delivered to your inbox with our free Cyber Daily.

Join & Write a Comment

Introduction Although it is an old technology, serial ports are still being used by many hardware manufacturers. If you develop applications in C#, Microsoft .NET framework has SerialPort class to communicate with the serial ports.  I needed to…
Performance in games development is paramount: every microsecond counts to be able to do everything in less than 33ms (aiming at 16ms). C# foreach statement is one of the worst performance killers, and here I explain why.
Illustrator's Shape Builder tool will let you combine shapes visually and interactively. This video shows the Mac version, but the tool works the same way in Windows. To follow along with this video, you can draw your own shapes or download the file…
In this tutorial you'll learn about bandwidth monitoring with flows and packet sniffing with our network monitoring solution PRTG Network Monitor (https://www.paessler.com/prtg). If you're interested in additional methods for monitoring bandwidt…

743 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

15 Experts available now in Live!

Get 1:1 Help Now