-
Доброго времени суток Читал много про хуки , но понять не смог. У меня есть просто приложение которое из мемо1 конвертирует текст в Dos кодировку и записывает полученный результат в мемо2. Использую вот такой код функции
function WinToDos(ASource: String): AnsiString;
var
Ch: PAnsiChar;
begin
Ch := AnsiStrAlloc(Length(ASource) + 1);
CharToOem(PChar(ASource), Ch);
Result := StrPas(Ch);
StrDispose(Ch)
end;
В программе
memo2.text:=WinToDos(memo1.text);
Хочу сделать хук WinAPI функции CharToOem, что бы моя функция не конвертировала данные с помощью функции CharToOem, а просто передавала не измененный данные в мемо2 Вот как это реализовать через SetWindowsHookEx не знаю. Предполагаю надо начинать с чтения отправляемых данных через WH_CALLWNDPROC и эти же данные передавать через WH_GETMESSAGE Возможно только что описал бред. В распоряжение Win7 и RAD 2010 Подскажите как это можно реализовать. Пример с комментариями по возможности или ссылку на подобный материал. Заранее благодарен. P.S. Программированием занимался в последний раз лет 7 назад, так что не судите строго.
-
> Dark_Ph0eNix (04.07.16 07:58)
> memo2.text:=WinToDos(memo1.text);
memo2.text:=memo1.text; ?
Если же приложение чужое, то перетащить текст можно путем SendMessage WM_SETTEXT/WM_GETTEXT.
-- Regards, LVT.
-
Leonid Troyanovsky спасибо мемо1 и мемо2 использованы в качестве наглядного примера использования функции CharToOem Но задача в том чтобы перехватывать именно вызов CharToOem и что бы подмененная функция выдавал те же данные что и получила
К примеру
var src: PChar dst: AnsiChar begin src:='й'; CharToOem(src, dst); showmessage(src); showmessage(dst); end;
Результатом будет вывод двух сообщений в первом будет "й", во втором будет "©".
А мне надо что бы при перехвате CharToOem в "dst" было "й" вместо "©".
Надеюсь понятно объяснил )))
-
Хукать планирую приложение которое получает данные из базы, конвертирует в оем и потом шлет в ком-порт. Из-за конвертирования в в оем русские и казахские символы передаются не правильные.
-
1 Dark_Ph0eNix , а как работала, и работали ли правильно, подопытная программа до того как Вы решили вспомнить сколько лет не программировали и почему уверенны что в ней есть вызов CharToOem ? 2 > Читал много про хуки , но понять не смог.Теперь много читайте про http://habrahabr.ru/post/178393/ 3 > и что бы подмененная функция выдавал те же данные что и получила но это Вас, скорее всего, не спасёт, так как дальше программа, всё равно эти данные будет воспринимать и передавать не как UnicodeString, а как AnsiString.
4 > и потом шлет в ком-порт Почитайте ёще про “com0com”. Напишите (или подумайте над пунктом б ) программу которая будет: a) получать данные с подопытной посредством виртуальных ком портов; б) преобразовывать их так ‘как нужно’; в) отправлять в реальный ком порт на внешнее устройство.
@ AnsiStrAlloc, StrDispose – где-то подсмотрели, или осознанно используете эти функции?
-
> NoUser ©
Спасибо большое за ссылку, ушел изучать что и как
> AnsiStrAlloc, StrDispose – где-то подсмотрели, или осознанно > используете эти функции?
Нашел на просторах интернета, код выполнял поставленную задачу, а именно преобразовывал текст из 1251 в дос.
> Dark_Ph0eNix , а как работала, и работали ли правильно, > подопытная программа до того как Вы решили вспомнить сколько > лет не программировали и почему уверенны что в ней есть > вызов CharToOem ?
Программа до этого работала нормально и сейчас работает нормально, только вот проблема в том что казахские символы в частности он преобразует в знак "_". По поводу вызова CharToOemA уверен т.к. предварительно поставил API Monitor, отловил исходный текст до преобразования, пробежался по списку функций которые работают с текстом, поставил брэйкпоинты, откорректировал текст который отдает функция CharToOemA и после этого в порт ушел правильный текст, по этому абсолютно уверен в использовании именно этой функции из user32.dll
-
А сколько будет стоить написание такого приложения? Может мне будет проще заплатить кому-нибудь чем ломать свой мозг?
-
-
> Dark_Ph0eNix (07.07.16 07:10) [5]Раз уж знакомы со словом брэйкпоинт, то на коленке можно сделать так: 1. Найти с помощью отладчика адрес памяти куда загрузчик помещает адрес нужной нам функции. 2. Разместить в директории программы длл-переходник на одну из системных длл, что даст возможность разместить в программе новую функцию и подменить на неё значение по адресу из пункта 1. -- Основная сложность, скорее всего, будет в поиске удобной длл. Посмотреть из каких длл и что вызывает программа можно этим инструментом http://www.dependencywalker.com/.-- Например, программы собранные в Delphi с Vcl, экспортируют несколько функций из Version.dll (да и всего там ~15 функций). Что идеально подходит для эксперимента. Код длл-переходника может быть таким: library Version;
uses Windows;
// ------
const cVersionDLL = '\Version.dll'; cVerQueryValue = 'VerQueryValue'; cGetFileVersionInfo = 'GetFileVersionInfo'; cGetFileVersionInfoSize = 'GetFileVersionInfoSize';
type TVerQueryValue = function (pBlock: Pointer; lpSubBlock: LPWSTR; var lplpBuffer: Pointer; var puLen: UINT): BOOL; stdcall; TGetFileVersionInfo = function (lptstrFilename: LPWSTR; dwHandle, dwLen: DWORD; lpData: Pointer): BOOL; stdcall; TGetFileVersionInfoSize = function (lptstrFilename: LPWSTR; var lpdwHandle: DWORD): DWORD; stdcall;
var OriVersionDLL : HModule; OriVerQueryValueA , OriVerQueryValueW : TVerQueryValue; OriGetFileVersionInfoA , OriGetFileVersionInfoW : TGetFileVersionInfo; OriGetFileVersionInfoSizeA , OriGetFileVersionInfoSizeW : TGetFileVersionInfoSize;
//
function OriDllLoad: Boolean; var s: string; begin Result := (OriVersionDLL <> 0); if not Result then begin SetLength(s, 1024); SetLength(s, GetSystemDirectory(PChar(s), Length(s))); OriVersionDLL := LoadLibrary(PChar(s + cVersionDLL)); if (OriVersionDLL <> 0) then begin OriVerQueryValueA := GetProcAddress(OriVersionDLL, cVerQueryValue+'A'); OriVerQueryValueW := GetProcAddress(OriVersionDLL, cVerQueryValue+'W'); OriGetFileVersionInfoA := GetProcAddress(OriVersionDLL, cGetFileVersionInfo+'A'); OriGetFileVersionInfoW := GetProcAddress(OriVersionDLL, cGetFileVersionInfo+'W'); OriGetFileVersionInfoSizeA := GetProcAddress(OriVersionDLL, cGetFileVersionInfoSize+'A'); OriGetFileVersionInfoSizeW := GetProcAddress(OriVersionDLL, cGetFileVersionInfoSize+'W'); Result := ( (@OriVerQueryValueA <> nil) and (@OriVerQueryValueW <> nil) and (@OriGetFileVersionInfoA <> nil) and (@OriGetFileVersionInfoW <> nil) and (@OriGetFileVersionInfoSizeA <> nil) and (@OriGetFileVersionInfoSizeW <> nil) ); end; end; end;
procedure OriDllFree; begin if (OriVersionDLL <> 0) then begin FreeLibrary(OriVersionDLL); OriVersionDLL := 0; end; end;
//
function VerQueryValueA(pBlock: Pointer; lpSubBlock: LPWSTR; var lplpBuffer: Pointer; var puLen: UINT): BOOL; stdcall; begin if ( OriDllLoad() ) then Result := OriVerQueryValueA(pBlock, lpSubBlock, lplpBuffer, puLen) else Result := False; end;
function GetFileVersionInfoA(lptstrFilename: LPWSTR; dwHandle, dwLen: DWORD; lpData: Pointer): BOOL; stdcall; begin if ( OriDllLoad() ) then Result := OriGetFileVersionInfoA(lptstrFilename, dwHandle, dwLen, lpData) else Result := False; end;
function GetFileVersionInfoSizeA(lptstrFilename: LPWSTR; var lpdwHandle: DWORD): DWORD; stdcall; begin if ( OriDllLoad() ) then Result := OriGetFileVersionInfoSizeA(lptstrFilename, lpdwHandle) else Result := 0; end;
function VerQueryValueW(pBlock: Pointer; lpSubBlock: LPWSTR; var lplpBuffer: Pointer; var puLen: UINT): BOOL; stdcall; begin if ( OriDllLoad() ) then Result := OriVerQueryValueW(pBlock, lpSubBlock, lplpBuffer, puLen) else Result := False; end;
function GetFileVersionInfoW(lptstrFilename: LPWSTR; dwHandle, dwLen: DWORD; lpData: Pointer): BOOL; stdcall; begin if ( OriDllLoad() ) then Result := OriGetFileVersionInfoW(lptstrFilename, dwHandle, dwLen, lpData) else Result := False; end;
function GetFileVersionInfoSizeW(lptstrFilename: LPWSTR; var lpdwHandle: DWORD): DWORD; stdcall; begin if ( OriDllLoad() ) then Result := OriGetFileVersionInfoSizeW(lptstrFilename, lpdwHandle) else Result := 0; end;
//
exports VerQueryValueA index 11 name cVerQueryValue+'A', VerQueryValueW index 14 name cVerQueryValue+'W', GetFileVersionInfoA index 1 name cGetFileVersionInfo+'A', GetFileVersionInfoW index 4 name cGetFileVersionInfo+'W', GetFileVersionInfoSizeA index 2 name cGetFileVersionInfoSize+'A', GetFileVersionInfoSizeW index 3 name cGetFileVersionInfoSize+'W';
// ------
type PCharToOemA = ^TCharToOemA; TCharToOemA = function (lpszSrc: LPCSTR; lpszDst: LPSTR): BOOL; stdcall;
const cMyExeName = 'Project.exe'; // ! OemFuncAddrFromDebuger : PCharToOemA = Pointer($005e0dac); // !!!
var OriginalCharToOemA : TCharToOemA;
function MyCharToOemA(lpszSrc: LPCSTR; lpszDst: LPSTR): BOOL; stdcall; begin OutputDebugString('Hi, MyFunc In Work!'); //// // My Code // ??? ////
// Result := ;
Result := OriginalCharToOemA(lpszSrc, lpszDst); // del if (lpszSrc <> nil) and (lpszDst <> nil) then // del if (lpszSrc^<>#0) then lpszDst^ := '!'; // ;) del end;
procedure DllMain(Reason: Integer); var s :String; begin case Reason of DLL_PROCESS_ATTACH: begin SetLength(s, 1024); SetLength(s, GetModuleFileName(0, PChar(s), Length(s))); OutputDebugString(PChar(s)); if (Pos(cMyExeName, s) > 0) then begin // OriginalCharToOemA := OemFuncAddrFromDebuger^; OemFuncAddrFromDebuger^ := @MyCharToOemA; OutputDebugString('Ok, MyFunc SetUp!'); end; end; // DLL_PROCESS_DETACH: OriDllFree; end; end;
begin DllMain(DLL_PROCESS_ATTACH); DllProc := @DllMain; end.
В строке 122 указывается название программы – для простой самопроверки, а в 123 адрес, найденный в отладчике адрес
005C9B66 E881AFE4FF call CharToOemA -> 00414AFC FF25B40D5E00 jmp dword ptr [$005e0dac] => или
00411D25 call dword ptr [__imp__CharToOemA@8 (041A0B4h)] =>
-
unit Unit1;
interface
uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs;
type TForm1 = class(TForm) procedure FormCreate(Sender: TObject); private { Private declarations } public { Public declarations } end;
var Form1: TForm1;
implementation
{$R *.dfm}
type PPatch = ^TPatch; TPatch = packed record A, B: DWORD; B8: Byte; lstrcpy: DWORD; // E: Word; C: DWORD; D: DWord; end; PRemoteDisableCharToOemParam = ^TRemoteDisableCharToOemParam; TRemoteDisableCharToOemParam = record strCharToOemA: string[11]; strUser32_dll: string[11];
GetProcAddress: function (hModule: HMODULE; lpProcName: LPCSTR): FARPROC; stdcall; GetModuleHandle: function (lpLibFileName: PChar): HMODULE; stdcall; VirtualProtect: function (lpAddress: Pointer; dwSize, flNewProtect: DWORD; var OldProtect: DWORD): BOOL; stdcall;
Patch: TPatch; end;
procedure RemoteDisableCharToOem(P: PRemoteDisableCharToOemParam); stdcall; var H: THandle; Ptr: PPatch; D: DWORD; begin // Функция заменяет код CharToOemA на вызов lstrcpyA H := P.GetModuleHandle(@P.strUser32_dll[1]); Ptr := P.GetProcAddress(H, @P.strCharToOemA[1]); P.VirtualProtect( Ptr, SizeOf(P.Patch), PAGE_EXECUTE_READWRITE, D); Ptr^ := P.Patch; end;
procedure DisableCharToOem(ProcessHandle: THandle); var Param: TRemoteDisableCharToOemParam; L: THandle; RemPtr: Pointer; RemCB: Pointer; W: Cardinal; Thread: THandle; begin L := GetModuleHandle(kernel32); Param.Patch.A := $042474FF; Param.Patch.B := $0C2474FF; Param.Patch.B8 := $B8; Param.Patch.C := $C883D0FF; Param.Patch.D := $0008C2FF; Param.strUser32_dll := 'user32.dll'#0; Param.strCharToOemA := 'CharToOemA'#0;
// Эти функции имеют одинаковый адрес во всех процессах Param.GetProcAddress := GetProcAddress(L, 'GetProcAddress'); // Почему-то тут нет буквы A Param.GetModuleHandle := GetProcAddress(L, 'GetModuleHandleA'); Param.VirtualProtect := GetProcAddress(L, 'VirtualProtect'); Param.Patch.lstrcpy := DWORD(GetProcAddress(L, 'lstrcpyA'));
// Выделяем память в удаленном процессе RemPtr := VirtualAllocEx( ProcessHandle, nil, 2048, MEM_COMMIT, PAGE_EXECUTE_READWRITE); Win32Check(RemPtr <> nil); try RemCB := Pointer(NativeUInt(RemPtr) + SizeOf(Param));
// Копируем туда код и патч Win32Check(WriteProcessMemory(ProcessHandle, RemPtr, @Param, SizeOf(Param), W)); Win32Check(WriteProcessMemory(ProcessHandle, RemCB, @RemoteDisableCharToOem, 2048 - SizeOf(Param), W));
// Запускаем патч Thread := CreateRemoteThread(ProcessHandle, nil, 0, RemCB, RemPtr, 0, W); Win32Check(Thread <> 0); try // Ждем завершения Win32Check(WaitForSingleObject(Thread, INFINITE) = WAIT_OBJECT_0); finally Win32Check(CloseHandle(Thread)); end; finally // Освобождаем удаленную память Win32Check(VirtualFreeEx(ProcessHandle, RemPtr, 0, MEM_RELEASE) <> nil); end;
end;
function WinToDos(ASource: AnsiString): AnsiString; begin SetLength(Result, Length(ASource)); CharToOem(PChar(ASource), @Result[1]); end;
procedure TForm1.FormCreate(Sender: TObject); begin // Тестируем до ShowMessage(WinToDos('Тест'));
// Патчим текущий процесс, но можно пропатчить любой, // полученный из CreateProcess или OpenProcess. DisableCharToOem(GetCurrentProcess);
// Тестируем после ShowMessage(WinToDos('Тест')); end;
end.
-
Писал-писал, и без ответа:(
-
Есть еще вариант: изменить формат в базе.
-
Удалено модератором
|