// 根据 dll 的输出表和 c 头文件,产生中间文件 。编译好,主要用于替换系统 dll, 监视
// 更详细的操作(windows 核心编程上有这种工具的介绍,忘记在哪张了)。 
// 避免过多的 hook 问题。

// 记得有前辈写过这个工具,但是没有找到。只好发点时间自己写了, 其中还有一些问题没有解决,需要手动修改
// 如果谁有那个版本的工具,给个链接 谢谢了

代码:



#pragma warning(disable : 4786)
#include <Windows.h>
#include <cstdio>
#include <ctime>
#include <cassert>
#include <list>
#include <string>
#include <vector>
#include <fstream>
#include <iostream>
using namespace std;

typedef vector<string> string_vector;

static int parse_cheader(const char* fname, string_vector& fun_def)
{
  ifstream ifile(fname);

  if ( !ifile )
    return 0;

  ifile.seekg(0, ios::end);
  const size_t fsize = ifile.tellg();
  ifile.seekg(0, ios::beg);
  
  auto_ptr<char> buf(new char[fsize + 1]);
  char* const _buf = buf.get();
  if ( _buf == NULL )
    return 0;
  
  ifile.read(_buf, fsize);
  ifile.close();

  _buf[fsize] = 0;
  
  bool skip1 = false;
  bool _skip1 = false;
  bool skip2 = false;
  int flag = -1;
  char* fun_name = NULL;

  for ( char* p = _buf; *p != 0; p++ )
  {
    // 跳过注释和宏
    if ( *p == '\n' )
    {
      skip1 = _skip1;
      _skip1 = false;

      p++;
    }
    
    if ( *p == '*' && p[1] == '/' )
    {
      skip2 = false;
      p += 2;
    }
    
    if ( *p == '\\' && skip1 )
    {
      _skip1 = true;
    }

    if ( skip1 || skip2 )
      continue;
    
    if ( *p == '/'  )
    {
      if ( p[1] == '/' )
      {
        skip1 = true;
        _skip1 = false;
      }
      else if ( p[1] == '*' )
        skip2 = true;
    }
    else if ( *p == '#' )
    {
      skip1 = true;
      _skip1 = false;
    }

    if ( skip1 || skip2 || strchr(" \t\n{}", *p) != 0 )
      continue;
    
    if ( fun_name == NULL )
    {
      fun_name = p;
      flag = -1;
    }
    else
    {
      if ( *p == ';' )
      {
        *p = 0;
        if ( flag == 0 && strncmp(fun_name, "typedef", 7) != 0 )
        {
      //    printf("%s;\n", fun_name);
          fun_def.push_back(fun_name);
        }
        fun_name = NULL;
      }
      else if ( *p == '(' ) 
      {
        if ( flag == -1 ) 
          flag++;
        flag++;
      }
      else if ( *p == ')' )
      {
        flag--;
      }
      else if ( strchr("\"{}", *p) != NULL )
      {
        fun_name = NULL;
      }
    }
  }

  return fun_def.size();
}

static long alig(long a, long n)
{
  long r = a % n;
  return (r == 0) ? a : (a + n) - r;
}

static long rav2raw(const void* image, long rav)
{
  PIMAGE_DOS_HEADER dosh = (PIMAGE_DOS_HEADER)image;
  PIMAGE_NT_HEADERS nth = (PIMAGE_NT_HEADERS)((char*)image + dosh->e_lfanew);
  PIMAGE_SECTION_HEADER secth = IMAGE_FIRST_SECTION(nth);

  if ( rav < secth->VirtualAddress )
    return rav;

  for ( unsigned i = 0; i < nth->FileHeader.NumberOfSections; i++ )
  {
    long a = alig(secth->VirtualAddress + secth->Misc.VirtualSize, nth->OptionalHeader.SectionAlignment);
    if ( secth->VirtualAddress <= rav && a > rav )
      return rav - secth->VirtualAddress + secth->PointerToRawData;

    secth++;
  }

  return -1;
}

static char* gen_def_fname(const char* cpp_fname, char* def_fname)
{
  strncpy(def_fname, cpp_fname, MAX_PATH);

  char* fname = strrchr(def_fname, '\\');
  if ( fname == NULL )
    fname = strrchr(def_fname, '//');

  if ( fname == NULL )
    fname = def_fname;
  else
    fname++;

  char* ext = strrchr(fname, '.');
  if ( ext == NULL )
    ext = strlen(def_fname) + def_fname;

  strcpy(ext, ".def");
  return def_fname;
}

int dll2cpp(
  const char* dll_fname, 
  const char* cpp_fname,
  string_vector& fun_def
  )
{
  ifstream dll_ifile(dll_fname, ios::binary);
  if ( !dll_ifile )
    return 0;
  
  ofstream cpp_ofile(cpp_fname);
  if ( !cpp_ofile )
    return 0;
  
  char def_fname[MAX_PATH];
  ofstream def_ofile(gen_def_fname(cpp_fname, def_fname));
  if ( !def_ofile )
    return 0;

  dll_ifile.seekg(0, ios::end);
  const dll_fsize = dll_ifile.tellg();
  dll_ifile.seekg(0, ios::beg);

  auto_ptr<char> ibuf(new char[dll_fsize]);
  char* const _ibuf = ibuf.get();
  if ( _ibuf == NULL )
    return 0;

  dll_ifile.read(_ibuf, dll_fsize);
  dll_ifile.close();

  PIMAGE_DOS_HEADER dosh;
  PIMAGE_NT_HEADERS nth;

  dosh = (PIMAGE_DOS_HEADER)_ibuf;
  nth = (PIMAGE_NT_HEADERS)(_ibuf + dosh->e_lfanew);
  if ( 
    dosh->e_magic != IMAGE_DOS_SIGNATURE || 
    nth->Signature != IMAGE_NT_SIGNATURE ||
    nth->FileHeader.NumberOfSections == 0 ||
    nth->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress == 0
    )
  {
    return 0;
  }
  
  long a;

  a = rav2raw(_ibuf, nth->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
  if ( a == -1 )
    return 0;
  PIMAGE_EXPORT_DIRECTORY expdir = (PIMAGE_EXPORT_DIRECTORY)(_ibuf + a);

  a = rav2raw(_ibuf, expdir->AddressOfNames);
  if ( a == -1 )
    return 0;
  PDWORD fun_name_a = (PDWORD)(_ibuf + a);

  a = rav2raw(_ibuf, expdir->AddressOfNameOrdinals);
  if ( a == -1 )
    return 0;
  PWORD fun_name_ord_a = (PWORD)(_ibuf + a);
  
  time_t t = time(NULL);
  cpp_ofile << 
    "/*\nThis File Created By Dll2CPP v0.1\n" << ctime(&t) << "*/\n" 
    "/* Written by dummyz@126.com (2007) */\n"
    "\n\n"
    "#define _WIN32_WINNT 0x0501\n"
    "#include <windows.h>\n\n"
    "#ifndef NAKED\n"
    "#define NAKED __declspec(naked)\n"
    "#endif\n"
    "#ifdef WINBASEAPI\n"
    "#undef WINBASEAPI\n"
    "#define WINBASEAPI\n"
    "#endif\n"
    "#ifdef WINUSERAPI\n"
    "#undef WINUSERAPI\n"
    "#define WINUSERAPI\n"
    "#endif\n\n"
    "BOOL WINAPI DllMain(HMODULE hModule, DWORD dwReason, LPVOID lpvReserved)\n"
    "{\n"
    "\tswitch ( dwReason )\n"
    "\t{\n"
    "\tcase DLL_PROCESS_ATTACH: break;\n"
    "\tcase DLL_PROCESS_DETACH: break;\n"
    "\tcase DLL_THREAD_ATTACH: break;\n"
    "\tcase DLL_THREAD_DETACH: break;\n"
    "\t}\n\n"
    "\treturn TRUE;\n"
    "}\n\n" << endl;
    
  def_ofile << "EXPORTS" << endl;
  for ( unsigned i = 0, j = 0; i < expdir->NumberOfFunctions; i++ )
  {
    bool ok = false;
    char buf[200];
    const char* name = NULL;
    const char* comment = NULL;

    if ( j < expdir->AddressOfNameOrdinals && fun_name_ord_a[j] == i )
    {
      char* name2 = _ibuf + rav2raw(_ibuf, fun_name_a[j]);
      const int name2_len = strlen(name2);

      for ( unsigned t = 0; t < fun_def.size(); t++ )
      {
        const string& str = fun_def[t];
        const char* p = strstr(str.c_str(), name2);
        if ( p != NULL && strchr(" \t\n", p[-1]) != NULL )
        {
          p += name2_len;
          if ( strchr(" \t\n(", *p) != NULL )
          {
            name = str.c_str();
            break;
          }
        }
      }
      
      if ( name == NULL )
      {
        sprintf(buf, "int WINAPI %s()", name2);
        name = buf;
        comment = "/* @这个函数没找到声明的原型 */";
      }
      
      j++;
    }
    else
    {
      sprintf(buf, "int WINAPI sub_ord%08X()", i);
      name = buf;
      comment = "/* @这个函数是由序号导出的 */";
    }
    
    if ( name != NULL )
    {
      char fun_name[200];
      for ( const char* p = strchr(name, '(') - 1, *q = NULL; p > name; p-- )
      {
        if ( q != NULL )
        {
          if ( strchr(" \t\n", *p) != NULL )
          {
            int len = q - p;
            
            strncpy(fun_name, ++p, len);
            fun_name[len] = 0;
            
            if ( comment != NULL )
              cpp_ofile << comment << endl;
            cpp_ofile << "/* \n";
            cpp_ofile << name << "\n*/\n";
            
            cpp_ofile << "NAKED int WINAPI Proxy_" << fun_name << "()\n";
            cpp_ofile << "{\n\t __asm jmp [" << fun_name << "]\n}\n\n";
            
            def_ofile << "\t" << fun_name << " = " << "Proxy_" << fun_name << "\t@" << i + expdir->Base << " PRIVATE\n";
            ok = true;
            break;
          }
        }
        else if ( strchr(" \t\n", *p) == NULL )
        {
          q = p;
        }
      }
    }
    
    if ( !ok )
      cout << "ERROR : " << i + expdir->Base << endl << name << endl;
  }
  
  return 0;
}

int main(int argc, char* argv[])
{
  string_vector fun_def;

  parse_cheader("D:\\PSDK\\Include\\winuser.h", fun_def);
  parse_cheader("D:\\PSDK\\Include\\winbase.h", fun_def);
  parse_cheader("D:\\PSDK\\Include\\WinCon.h", fun_def);
  parse_cheader("D:\\PSDK\\Include\\WinNls.h", fun_def);
  parse_cheader("D:\\PSDK\\Include\\WinNt.h", fun_def);
  parse_cheader("D:\\PSDK\\Include\\LZExpand.h", fun_def);
  dll2cpp("c:\\windows\\system32\\kernel32.dll", "c:\\1.cpp", fun_def);

  return 0;
}