Go4Expert

Go4Expert (http://www.go4expert.com/)
-   C++ (http://www.go4expert.com/articles/cpp-tutorials/)
-   -   glTest1: Intercept Opengl32 with GPA (http://www.go4expert.com/articles/gltest1-intercept-opengl32-gpa-t29603/)

david_BS 9Apr2013 22:16

glTest1: Intercept Opengl32 with GPA
 
1 Attachment(s)
LEVEL: BEGINNER, Test Environment: WinXP SP3

This is a demonstration of how Opengl32 with GPA can be applied an IAT HOOK to intercept functions in a process. In this case, it is about an EXE which uses some functions from Opengl32 to create a window and render an image.

http://imgs.g4estatic.com/intercept-...2-gpa/gl2w.png

To make use out of the Opengl32 functions in an EXE like in this case, it can be done by dynamic linking (with .DLL) or with static linking (with .LIB)
Here I give a few links where to get information:To make the example .EXE, I took an example code which is offered in the official site of Opengl.The original example program uses static linking, but to make this demostration possible, I had to modify it. The modifications are made for 3 of the function calls to Opengl32, which were chosen to make this demostration. They are: glBegin, glBlendFunc, glViewport

To know anything about them you’ll need to get a manual or make a search in the official Opengl site.

We want intercept these 3 functions so we can change the behaviour of the program, the idea is to change what the program shows by the screen.

What is done in the .EXE, is to fix the 3 function calls, that normally are called by static linking. In change, now they were modified to make the linking to be dynamic. So that, it were declared pointers to function and the addresses in Opengl32 are resolved in runtime. This is done with GetProcAddress.

Now we know that the sample .EXE makes use of GetProcAddress to get the addresses of the 3 said functions, we’re going to intercept GetProcAddress so it will return other addresses than the originals. Meaning, the addresses of our hooks. Hooks will be within a DLL that we created, and will be loaded to the process. Once loaded to the process, the EXE’s IAT will be patched at the entry of GetProcAddress, that way GetProcAddress is intercepted.

Checking the code of the .EXE:

The necessary include files, and required static libraries to make compilation possible.
Code:

#pragma comment (lib, "opengl32.lib")
#pragma comment (lib, "GLUT32/glut32.lib")
#include <windows.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
 
#include "GLUT32/glut.h"
#include <gl\gl.h>
#include <gl\glu.h>
 
#include "texture.h"

The pointers to function for the 3 functions we’ll intercept.
Code:

// Opengl32 es APIENTRY
typedef void(__stdcall* t_glBegin)(GLenum);
typedef void(__stdcall* t_glBlendFunc)(GLenum, GLenum);
typedef void(__stdcall* t_glViewport)(GLint,GLint,GLsizei,GLsizei);
 
// Declaramos unos punteros que van a contener la dirección de las funciones OGL32 que usemos.
t_glBegin pOrig_glBegin = NULL;
t_glBlendFunc pOrig_glBlendFunc = NULL;
t_glViewport pOrig_glViewport = NULL;

Entry point, as we can see, the DLL is loaded with a simple LoadLibrary call. We make no DLL injection or any other method to load a DLL. “glhack1.dll” is the DLL which will make the IAT patch itself, and also it contains the hooks for GetProcAddress and Opengl32.
Code:

int main(int argc, char **argv)
{
  SetConsoleTitle("glTest");
 
  int opc=0;
  while( 1){
 
                              system("cls");
                              printf("Bienvenido!\n");
                              printf("1: Interceptar OPENGL32\n");
                              printf("2: NO Interceptar OPENGL32\n");
                              printf("3: Salir\n");
                              scanf("%d",&opc);
 
                              if(opc == 1||opc == 2||opc == 3) break;
  }
 
  if(opc==3) ExitProcess(45);
 
  if(opc==1) //Al cargar la DLL, esta instala el hook a GPA para poder interceptar OGL32
  {
                  if(!LoadLibrary("glhack1.dll")){
 
                                MessageBox(0,0,0,0);
                                ExitProcess(0);
                  }
  }
 
  printf("\n");
  printf("EXE: GPA 0x%X\n", GetProcAddress);
  printf("EXE: glBegin 0x%X\n", glBegin);
  if(GetModuleHandle("opengl32.dll"))
  {
                  pOrig_glBegin = (t_glBegin)GetProcAddress(GetModuleHandle("opengl32.dll"), "glBegin");
                  pOrig_glBlendFunc = (t_glBlendFunc)GetProcAddress(GetModuleHandle("opengl32.dll"), "glBlendFunc");
                  pOrig_glViewport = (t_glViewport)GetProcAddress(GetModuleHandle("opengl32.dll"), "glViewport");
                  printf("EXE: glBegin 0x%X\n", pOrig_glBegin);
                  printf("EXE: glBlendFunc 0x%X\n", pOrig_glBlendFunc);
                  printf("EXE: glViewport 0x%X\n", pOrig_glViewport);
  }
  else
  {
                  MessageBox(0,0,0,0);
                  ExitProcess(0);
                  return 0;
  }
 
  glutInit(&argc, argv);
  glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE);
  glutInitWindowSize(450, 450);
  glutCreateWindow("glTest");
  // glutFullScreen();
  init(argv[1]);
  glutDisplayFunc(display);
  glutKeyboardFunc(key);
  glutReshapeFunc(reshape);
  glutIdleFunc(tick);
  glutMainLoop();
  return 0;            /* ANSI C requires main to return int. */
}
 
//

This functions are original from the sample code at opengl.org. Changes seen are the original function calls for the 3 chosen functions. They were changed for the pointers to function we created before.
Code:

void bfunc(void)
{
  static int state;
  if (state ^= 1)
  {
    pOrig_glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    glEnable(GL_BLEND);
  } else {
    glDisable(GL_BLEND);
  }
}

Code:

void bfunc(void)
{
  static int state;
  if (state ^= 1)
  {
    pOrig_glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    glEnable(GL_BLEND);
  } else {
    glDisable(GL_BLEND);
  }
}

Code:

void display(void)
{
  glClear(GL_COLOR_BUFFER_BIT);
  glPushMatrix();
  glTranslatef(transx, transy, 0.f);
  glRotatef(rotx, 0., 1., 0.);
  glRotatef(roty, 1., 0., 0.);
  glScalef(scale, scale, 0.);
  pOrig_glBegin(GL_POLYGON);
  glTexCoord2f(0.0, 0.0);
  glVertex2f(-1.0, -1.0);
  glTexCoord2f(1.0, 0.0);
  glVertex2f(1.0, -1.0);
  glTexCoord2f(1.0, 1.0);
  glVertex2f(1.0, 1.0);
  glTexCoord2f(0.0, 1.0);
  glVertex2f(-1.0, 1.0);
  glEnd();
  glPopMatrix();
  glutSwapBuffers();
}

Code:

void reshape(int w, int h)
{
  pOrig_glViewport(-50, -50, w+120, h+120);
}

The DLL makes a patch to the EXE’s IAT, and we got a function that makes all this, I got it from here:
http: //50hz.ws/devel/iathook.c.txt

I modified it because it was giving some problems.
Code:

BOOL HookIAT(char* szModule, char* szFunc, DWORD dwOwn, DWORD& dwOrg)
{
    DWORD dwBase = (DWORD)GetModuleHandle(NULL);
    PIMAGE_DOS_HEADER pDosHdr = (PIMAGE_DOS_HEADER)dwBase;
    PIMAGE_NT_HEADERS pNTHdr = (PIMAGE_NT_HEADERS)(dwBase + pDosHdr->e_lfanew);
    DWORD ImportData = (DWORD)pNTHdr->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
    PIMAGE_IMPORT_DESCRIPTOR pImportD = (PIMAGE_IMPORT_DESCRIPTOR)(dwBase + ImportData);
    while(pImportD->Name != 0)
    {
                              // CUIDADO! En estas estructuras se encuentran strings no terminadas en 0
                              // por lo que STRCMP no sirve.
                              // Un cambio fácil puede ser usar STRSTR que encuentra una cadena dentro de otra.
                              //            if(!strcmp((char*)(dwBase + pImportD->Name), szModule))
        if(!strstr((char*)(dwBase + pImportD->Name), szModule))
            break;
        pImportD++;
    }
 
                //printf("pImportD->Name: %s\n",(char*)(dwBase + pImportD->Name));
                //system("pause");
    if(pImportD->Name == 0) return FALSE;
                //printf("pImportD->Name: 0x%X\n",pImportD->Name);
                //system("pause");
 
    PIMAGE_THUNK_DATA pThunk = (PIMAGE_THUNK_DATA)(dwBase + pImportD->FirstThunk);
    DWORD OrgFunc = (DWORD)GetProcAddress(GetModuleHandle(szModule), szFunc);
    while(pThunk->u1.Function != 0)
    {
        if(pThunk->u1.Function == (DWORD*)OrgFunc)
        {
            dwOrg = OrgFunc;
            DWORD dwOldProt = 0;
            VirtualProtect((void*)&pThunk->u1.Function, 4, PAGE_EXECUTE_READWRITE, &dwOldProt);
            pThunk->u1.Function = (DWORD*)dwOwn;
            VirtualProtect((void*)&pThunk->u1.Function, 4, dwOldProt, &dwOldProt);
            if(pThunk->u1.Function == (DWORD*)dwOwn)
                return TRUE;
            else
                return FALSE;
        }
        pThunk++;
    }
    return FALSE;
}

Now check the DLL code, see main.cpp
Code:

//
// By 85
// HookIAT (h1web, Thanks to Ashkbiz Danehkar)
// elhacker.net
// etalking.com.ar
// 2013
//
 
///////////////////////////////////////////////////////////////////////////////////////////////////////////
 
#define WIN32_LEAN_AND_MEAN
#include<windows.h>
#include<stdio.h>
#include<stdlib.h>
#include"opengl.h"
 
///////////////////////////////////////////////////////////////////////////////////////////////////////////
 
FARPROC (WINAPI* pGetProcAddress) ( HMODULE hModule, LPCSTR lpProcName );
 
//
FARPROC WINAPI newGetProcAddress(HMODULE hModule, LPCSTR lpProcName)
{
                FARPROC nResult;
                nResult=GetProcAddress(hModule, lpProcName);
                if (HIWORD(lpProcName))
                {
                              if (!lstrcmp(lpProcName, "GetProcAddress"))
                              {
                                              return (FARPROC) &newGetProcAddress;
                              }
                              else
                              {
                                              CheckForOpenGlHook(&nResult, lpProcName);
        }
                }
                return nResult;
}
 
//
BOOL HookIAT(char* szModule, char* szFunc, DWORD dwOwn, DWORD& dwOrg)
{
    // Ya mostrado
}
 
//
bool WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved)
{
                if (fdwReason==DLL_PROCESS_ATTACH)
                {
                              //printf("GetProcAddress 0x%X\n", GetProcAddress);// No refenciar GPA antes!
                              if(!HookIAT("kernel32.dll","GetProcAddress",(DWORD)newGetProcAddress,
                                              (DWORD&)pGetProcAddress)){
 
                                              MessageBox(0,0,0,0);
                                              return (false);
                              }
 
                              printf("\n");
                              printf("DLL: newGetProcAddress 0x%X\n", newGetProcAddress);
                              printf("DLL: GetProcAddress 0x%X\n", GetProcAddress);
                              printf("DLL: pGetProcAddress 0x%X\n", pGetProcAddress);
 
                }
                return (true);
}

The hooks are the following, see that it were made some changes so the program shows a different result.
And remember that the GetProcAddress hook has the task of changing the original Opengl32 addresses to the addresses of our hooks. The original addresses are needed, so they are saved in the pointers to functions we created before.

Opengl32.cpp
Code:

//
// By 85
// elhacker.net
// etalking.com.ar
// 2013
//
 
///////////////////////////////////////////////////////////////////////////////////////////////////////////
 
#pragma comment(lib, "opengl32.lib")
#include<windows.h>
#include<stdio.h>
#include "opengl.h"
 
///////////////////////////////////////////////////////////////////////////////////////////////////////////
 
// Opengl32 es APIENTRY
typedef void(__stdcall* t_glBegin)(GLenum);
typedef void(__stdcall* t_glBlendFunc)(GLenum, GLenum);
typedef void(__stdcall* t_glViewport)(GLint,GLint,GLsizei,GLsizei);
 
t_glBegin pOrig_glBegin = NULL;
t_glBlendFunc pOrig_glBlendFunc = NULL;
t_glViewport pOrig_glViewport = NULL;
 
bool once=false;
bool oglSubtractive = false;
bool NewDimension = true;
 
int posx = 200;
int posy = 200;
int neww = 50;
int newh = 50;
 
//
void __stdcall HOOK_glBegin(GLenum mode)
{
                if(!once){
                              once=true;
                }
 
                if (mode==GL_POLYGON)
                {
                    glClearColor(1.0, 1.0, 1.0, 1.0);
                    glColor3f(0, 0, 0);
                }
 
                (*pOrig_glBegin)(mode);
}
 
void __stdcall HOOK_glBlendFunc(GLenum sfactor, GLenum dfactor)
{
                if(oglSubtractive){
                              glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
 
                } else {
                              glBlendFunc(sfactor,dfactor);
                }
}
 
void __stdcall HOOK_glViewport( GLint x,GLint y,GLsizei width,GLsizei height )
{
                if(NewDimension){
 
                              (*pOrig_glViewport)(posx,posy,neww,newh);
                }
                else
                {
                              (*pOrig_glViewport)(x,y,width,height);
                }
}
 
void CheckForOpenGlHook(FARPROC* pProc,LPCTSTR lpProcName)
{
                if (!strcmp(lpProcName,"glBegin"))
                {
                              pOrig_glBegin = (t_glBegin)*pProc;
                              *pProc = (FARPROC)&HOOK_glBegin;
                }
                else if(!strcmp(lpProcName,"glBlendFunc"))
                {
                                              pOrig_glBlendFunc = (t_glBlendFunc)*pProc;
                                              *pProc = (FARPROC)&HOOK_glBlendFunc;
                }
                else if(!strcmp(lpProcName,"glViewport"))
                {
                                              pOrig_glViewport = (t_glViewport)*pProc;
                                              *pProc = (FARPROC)&HOOK_glViewport;
                }
}

I hope you liked it. This is a basic tutorial so I just used a simple IAT patch. You can go and use a more advanced hooking method. The program gives you the option of modifying or not Opengl32:

http://imgs.g4estatic.com/intercept-...32-gpa/gl1.png

Used files:
http://imgs.g4estatic.com/intercept-...2-gpa/gl4p.png

Results:
http://imgs.g4estatic.com/intercept-...2-gpa/gl3a.png

If you ask me why I make the EXE to use GetProcAddress when it wasn’t necessary, the answer is that some games did in that way, and it was good to show an application of hooking GetProcAddress.


All times are GMT +5.5. The time now is 20:14.