{*******************************************************}
{                                                       }
{       Tocsg.Kernel32                                  }
{                                                       }
{       Copyright (C) 2021 kkuzil                       }
{                                                       }
{*******************************************************}

unit Tocsg.Kernel32;

interface

uses
  WinApi.Windows;

const
  PROCESS_QUERY_LIMITED_INFORMATION = $1000;

  GET_MODULE_HANDLE_EX_FLAG_PIN = $00000001;
  GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS = $00000004;
  GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT = $00000002;

  ATTACH_PARENT_PROCESS = DWORD(-1); // for AttachConsole() API

type
  PHMODULE = ^HMODULE;

  TQueryFullProcessImageName  = function(hProcess: THandle; dwFlags: DWORD; pBuffer: PChar; var dwSize: DWORD): DWORD; stdcall;
  TGetModuleHandleEx = function(dwFlags: DWORD; lbModuleName: PChar; phModule: PHMODULE): BOOL; stdcall;
  TProcessIdToSessionId = function(dwProcessId: DWORD; var dwSessionId: DWORD): BOOL; stdcall;

// 64 환경에서 32 응용 프로그램으로 system32에 접근 할때 자동을 syswow64로 변경되지 않도록 함
  TWow64DisableWow64FsRedirection = function(var pOldVal: Pointer): BOOL; stdcall;
  TWow64RevertWow64FsRedirection = function(pOldVal: Pointer): BOOL; stdcall;

  TAttachConsole = function(dwProcessID: DWORD): BOOL; stdcall;
  TFreeConsole = function: BOOL; stdcall;


function QueryFullProcessImageName(hProcess: THandle; dwFlags: DWORD; pBuffer: PChar; var dwSize: DWORD): DWORD;
function GetModuleHandleEx(dwFlags: DWORD; lpModuleName: PChar; phModule: PHMODULE): BOOL;
function ProcessIdToSessionId(dwProcessId: DWORD; var dwSessionId: DWORD): BOOL;

function Wow64DisableWow64FsRedirection(var pOldVal: Pointer): BOOL;
function Wow64RevertWow64FsRedirection(pOldVal: Pointer): BOOL;

function AttachConsole(dwProcessId: DWORD): BOOL;
function FreeConsole: BOOL;

implementation

var
  _hKernel32: THandle = 0;
  _fnQueryFullProcessImageName: TQueryFullProcessImageName = nil;
  _fnGetModuleHandleEx: TGetModuleHandleEx = nil;
  _fnProcessIdToSessionId: TProcessIdToSessionId = nil;
  _fnWow64DisableWow64FsRedirection: TWow64DisableWow64FsRedirection = nil;
  _fnWow64RevertWow64FsRedirection: TWow64RevertWow64FsRedirection = nil;
  _fnAttachConsole: TAttachConsole = nil;
  _fnFreeConsole: TFreeConsole = nil;

function InitKernel32Procedure: Boolean;
begin
  if _hKernel32 = 0 then
  begin
    _hKernel32 := GetModuleHandle(kernel32);
    if _hKernel32 <> 0 then
    begin
{$IFDEF UNICODE}
      @_fnQueryFullProcessImageName := GetProcAddress(_hKernel32, 'QueryFullProcessImageNameW'); // vista 이상
      @_fnGetModuleHandleEx := GetProcAddress(_hKernel32, 'GetModuleHandleExW'); // xp 이상
{$ELSE}
      @_fnQueryFullProcessImageName := GetProcAddress(_hKernel32, 'QueryFullProcessImageNameA');
      @_fnGetModuleHandleEx := GetProcAddress(_hKernel32, 'GetModuleHandleExA');
{$ENDIF}
      @_fnProcessIdToSessionId := GetProcAddress(_hKernel32, 'ProcessIdToSessionId');
      @_fnWow64DisableWow64FsRedirection := GetProcAddress(_hKernel32, 'Wow64DisableWow64FsRedirection');
      @_fnWow64RevertWow64FsRedirection := GetProcAddress(_hKernel32, 'Wow64RevertWow64FsRedirection');
      @_fnAttachConsole := GetProcAddress(_hKernel32, 'AttachConsole');
      @_fnFreeConsole := GetProcAddress(_hKernel32, 'FreeConsole');
    end;
  end;
  Result := _hKernel32 <> 0;
end;

function QueryFullProcessImageName(hProcess: THandle; dwFlags: DWORD; pBuffer: PChar; var dwSize: DWORD): DWORD;
begin
  if InitKernel32Procedure and Assigned(_fnQueryFullProcessImageName) then
    Result := _fnQueryFullProcessImageName(hProcess, dwFlags, pBuffer, dwSize)
  else Result := 0;
end;

function GetModuleHandleEx(dwFlags: DWORD; lpModuleName: PChar; phModule: PHMODULE): BOOL;
begin
  if InitKernel32Procedure and Assigned(_fnGetModuleHandleEx) then
    Result := _fnGetModuleHandleEx(dwFlags, lpModuleName, phModule)
  else Result := FALSE;
end;

function ProcessIdToSessionId(dwProcessId: DWORD; var dwSessionId: DWORD): BOOL;
begin
  if InitKernel32Procedure and Assigned(_fnProcessIdToSessionId) then
    Result := _fnProcessIdToSessionId(dwProcessId, dwSessionId)
  else Result := FALSE;
end;

// 사용 = Wow64DisableWow64FsRedirection(nil)
function Wow64DisableWow64FsRedirection(var pOldVal: Pointer): BOOL;
begin
  if InitKernel32Procedure and Assigned(_fnWow64DisableWow64FsRedirection) then
    Result := _fnWow64DisableWow64FsRedirection(pOldVal)
  else Result := FALSE;
end;

// 사용 = Wow64RevertWow64FsRedirection(nil)
function Wow64RevertWow64FsRedirection(pOldVal: Pointer): BOOL;
begin
  if InitKernel32Procedure and Assigned(_fnWow64RevertWow64FsRedirection) then
    Result := _fnWow64RevertWow64FsRedirection(pOldVal)
  else Result := FALSE;
end;

function AttachConsole(dwProcessId: DWORD): BOOL;
begin
  if InitKernel32Procedure and Assigned(_fnAttachConsole) then
    Result := _fnAttachConsole(dwProcessId)
  else Result := FALSE;
end;

function FreeConsole: BOOL;
begin
  if InitKernel32Procedure and Assigned(_fnFreeConsole) then
    Result := _fnFreeConsole
  else Result := FALSE;
end;

end.
