Большой Воронежский Форум
» Программирование>перехват WinApi GetLocalTime
Dream Worker 20:16 19.01.2009
Пытался повторить по примеру, взятому у MS_REM
http://www.wasm.ru/article.php?article=apihook_1
пример AdwareBox

Но во первых в Делфи GetLocalTime объявлена как процедура а не функция, во вторых мне не особо понятно смысл значений


Сообщение от :
кусок кода

Procedure SetHook();
var
Khernel32: dword;
Bytes: dword;
begin
Khernel32 := GetModuleHandle('Kernel32.dll');
GltAdr := GetProcAddress(Khernel32, 'GetLocalTime');
ReadProcessMemory(INVALID_HANDLE_VALUE, GltAdr, @OldGlt, SizeOf(OldCode), Bytes);
JmpGlt.PuhsOp := $68;
JmpGlt.PushArg := @NewGetLocalTime;
JmpGlt.RetOp := $C3;
WriteProcessMemory(INVALID_HANDLE_VALUE, GltAdr, @JmpGlt, SizeOf(far_jmp), Bytes);
end;

Сообщение от :
JmpGlt.PuhsOp := $68;
JmpGlt.RetOp := $C3;

Я видел множество примеров на C++ или на ASM, но в них, я к сожалению, не силен.
Если кому не тяжело, посоветуйте как нужно исправить код. спс. [Ответ]
Part!zan 21:17 19.01.2009

Сообщение от Dream Worker:
объявлена как процедура а не функция

А в чем, собсно, разница?

Сообщение от Dream Worker:
во вторых мне не особо понятно смысл значений

Это машкоды. Зачем тебе такие извращения? В нете масса примеров, написанных без подобных извратов.

Сообщение от Dream Worker:
множество примеров на C++

Они гораздо понятнее, чем эти мегакульхацкерные выпендрёжи. Напиши, что тебе не понятно в них.

Кстати, ты случаем, не вирус пишешь? ) Если нет, то тебе, скорее всего, вовсе не нужны такие изощренные методы внедрения. [Ответ]
dn2k4 09:08 20.01.2009

Сообщение от Part!zan:
В нете масса примеров, написанных без подобных извратов.

+1
Этот кусок кода не надо править - его надо выкинуть. Здесь в начала кода перехватываемой функции создается конструкция:
Код:
push <новый адрес обработчика>
ret
выполнение которой приводит к передаче управления на твою функцию.

Такой подход был хорош под DOS и под Win16. В современных системах с вытесняющей многозадачностью в момент между установкой первого и второго байта "патча" функция может понадобится другому процессу, который в лучшем случае благополучно рухнет, а в худшем - вынесет тебе половину системы.

Единственно вменяемое решение - править таблицу импорта модуля. Ищи, например, книгу: Джеффри РИХТЕР. "Создание эффективных WIN32-приложений" (по моему оно так называется, под рукой сейчас нет). [Ответ]
MadFish 11:30 20.01.2009
Гыы повеселило!!! Не пробовал (дельфи нет под рукой) а GPF не прилетит в момент записи в системный процесс? [Ответ]
dn2k4 17:17 20.01.2009
MadFish, хехе, а ну ка, где там системный процесс? =) [Ответ]
MadFish 17:23 20.01.2009
а чё кернел32 не на 0 кольце разве работает??? [Ответ]
Part!zan 22:26 20.01.2009

Сообщение от dn2k4:
в момент между установкой первого и второго байта "патча" функция может понадобится другому процессу

А в коде, который этот кусок использует, автор предусмотрительно останавливает треды... Но метод все равно изуверский и чисто вирусовый, называется сплайсинг. Делается с целью скрытия перехвата.

Сообщение от MadFish:
чё кернел32 не на 0 кольце разве работает

С какого перепугу? Этак каждое приложение юзермоды, подключившее kernel32.dll (а это практически любое виндовое приложение), получит реальную возможность завалить систему. [Ответ]
MadFish 10:02 21.01.2009

Сообщение от Part!zan:
С какого перепугу? Этак каждое приложение юзермоды, подключившее kernel32.dll (а это практически любое виндовое приложение), получит реальную возможность завалить систему.

Сори, я конечно может быть и нуб в этом вопросе но всегда считал что Kernel32.dll это свалка винапишных вызовов и менеджер памяти. Грузится и юзается ядром в том числе. И предполагается что с GDT и TSS можно работать только из 0 кольца. Киньте в меня ссылкой где можно почитать в инете или скачать микрософтовский DDK. [Ответ]
Part!zan 21:33 21.01.2009

Сообщение от MadFish:
всегда считал что Kernel32.dll это свалка винапишных вызовов и менеджер памяти. Грузится и юзается ядром в том числе

Ты путаешь с ntdll.dll. Ее функциями действительно пользуются драйверы ядра и, в том числе, kernel32.dll. Но даже если программа юзермоды напрямую подключит ntdll.dll, это вовсе не значит, что она автоматически начнет работать в ring0. Длл сама по себе нигде не выполняется и лишь содержит код, который выполняется в других процессах. И только от самого процесса зависит, на каком уровне он будет работать, а вовсе не от используемых длл.

Сообщение от MadFish:
скачать микрософтовский DDK

microsoft.com, а еще на торрентах есть. [Ответ]
MadFish 22:47 21.01.2009

Сообщение от Part!zan:
Ты путаешь с ntdll.dll.

Погодте... Например список экспортируемых функций kernel32.dll ... бла-бла-бла... HeapAlloc... бла-бла-бла...

Сообщение от Part!zan:
о даже если программа юзермоды напрямую подключит ntdll.dll, это вовсе не значит, что она автоматически начнет работать в ring0.

А я и не утверждал этого! Вызов произойдет понятное дело ЧЕРЕЗ вентель. А вот попытка записать в сегмент кода пошлет далеко и надолго вместе с GPF-ом...

Сообщение от Part!zan:
Длл сама по себе нигде не выполняется и лишь содержит код, который выполняется в других процессах

А вот это неверное утверждение!!! Никто мне не помешает при инициализации dll запустить поток и будет он у меня шарашить как проклятый!!!

Сообщение от Part!zan:
microsoft.com

Там он за деньги... пошел искать в торентах...
[Ответ]
dn2k4 23:08 21.01.2009

Сообщение от Part!zan:
автор предусмотрительно останавливает треды

Угу. Но если мне не изменяет память, то WriteProcessMemory пишет в область памяти, которая общая отмаппированая, там только seDebugPrivilege (которое по умолчанию у администраторов есть) и нужно. Так что треды других процессов, использующих dll, тоже придется тормозить. Что, в общем-то нетривиально и делает эту затею еще более извратной.

UPD: Память таки изменяет. Посморел таки в msdn - там хендл процесса нужен, правится его память. Значит надо возится с ToolHelpAPI, что тоже довольно через одно место.

Сообщение от MadFish:
А вот это неверное утверждение!!! Никто мне не помешает при инициализации dll запустить поток и будет он у меня шарашить как проклятый!!!

Вот только инициализация dll сама по себе, без процесса, который ее загружает, не происходит. В результате "шарашить как проклятый" будет код, находящийся в адресном пространстве и с правами твоего процесса.

И ты тоже Рихтера почитай - "Создание эффективных WIN32-приложений с учетом специфики 64-разрядной версии Windows" [Ответ]
Part!zan 23:57 21.01.2009

Сообщение от MadFish:
HeapAlloc

Эээ. Ну и чо? Это что-то доказывает?

Сообщение от MadFish:
попытка записать в сегмент кода пошлет далеко и надолго вместе с GPF-ом

С какой стати?

Сообщение от MadFish:
при инициализации dll запустить поток

Пардон, а какое этот поток будет отношение к длл? Он сам по себе, длл - сама по себе.

Сообщение от dn2k4:
треды других процессов, использующих dll, тоже придется тормозить

Он так и делает, насколько я понял. [Ответ]
MadFish 09:19 22.01.2009

Сообщение от dn2k4:
Вот только инициализация dll сама по себе, без процесса, который ее загружает, не происходит.

Ага, только например есть такая милая штучка как DCOM dll грузится и инициализируется не только не в адресном пространстве процесса а и вообще на физически другой машине

Сообщение от :
В результате "шарашить как проклятый" будет код, находящийся в адресном пространстве и с правами твоего процесса.

Угу, а если dll загрузило ядро? Вопрос у меня в том и был какой DPL у сегмента кода kernel32.dll.
Ладно пошел курить DDK и Рихтера на закуску, вернусь расскажу


Сообщение от Part!zan:
С какой стати?

Если DPL сегмента кода kernel32 будет ниже CPL процесса прилетит GPF


Сообщение от Part!zan:
Пардон, а какое этот поток будет отношение к длл? Он сам по себе, длл - сама по себе.

эээ не понял как это сам по себе? кусок кода dll шарашит и он сам по себе?
[Ответ]
Part!zan 19:49 22.01.2009
MadFish, короче, длл работает в контексте потока, ее подключившего. Независимо от "вероисповедания и цвета кожи" длл. Если у потока есть нужные привилегии - все будет пучком, не будет - прога обломается. Длл - всего лишь абстрактный код. [Ответ]
Dream Worker 02:00 23.01.2009

Сообщение от Part!zan:
Кстати, ты случаем, не вирус пишешь? ) .

Да нет, просто некоторые программы не просто имеют триальный период а просто не работают помле определенной даты, тут даже не сторлько халява - к примеру на работе - работа с клиентом БД на редактирование возможно только в 2008 году, а теперь его можно только просматривать (проверяется системное время). Можно конешно время в виндову переводить - но это неудобно.
Вот и хотлось получить возможность "утанавливать" время отдельно для выбранного приложения. [Ответ]
Dream Worker 05:19 25.01.2009

Сообщение от :
library TimeShift;
uses
Windows,TLHelp32;

type
OldCode = packed record
One: dword;
two: word;
end;


far_jmp = packed record
PuhsOp: byte;
PushArg: pointer;
RetOp: byte;
end;

var
JmpGlt : far_jmp;
OldGlt : OldCode;
GltAdr : pointer;

JmpGst : far_jmp;
OldGst : OldCode;
GstAdr : pointer;

Function OpenThread(dwDesiredAccess: dword;
bInheritHandle: bool;
dwThreadId: dword): dword; stdcall;
external 'kernel32.dll';


Procedure StopThreads;
var
h, CurrTh, ThrHandle, CurrPr: dword;
Thread: TThreadEntry32;
begin
CurrTh := GetCurrentThreadId;
CurrPr := GetCurrentProcessId;
h := CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
if h <> INVALID_HANDLE_VALUE then
begin
Thread.dwSize := SizeOf(TThreadEntry32);
if Thread32First(h, Thread) then
repeat
if (Thread.th32ThreadID <> CurrTh) and (Thread.th32OwnerProcessID = CurrPr) then
begin
ThrHandle := OpenThread(0002, false, Thread.th32ThreadID);
if ThrHandle>0 then
begin
SuspendThread(ThrHandle);
CloseHandle(ThrHandle);
end;
end;
until not Thread32Next(h, Thread);
CloseHandle(h);
end;
end;

Procedure RunThreads;
var
h, CurrTh, ThrHandle, CurrPr: dword;
Thread: TThreadEntry32;
begin
CurrTh := GetCurrentThreadId;
CurrPr := GetCurrentProcessId;
h := CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
if h <> INVALID_HANDLE_VALUE then
begin
Thread.dwSize := SizeOf(TThreadEntry32);
if Thread32First(h, Thread) then
repeat
if (Thread.th32ThreadID <> CurrTh) and (Thread.th32OwnerProcessID = CurrPr) then
begin
ThrHandle := OpenThread(2, false, Thread.th32ThreadID);
if ThrHandle>0 then
begin
ResumeThread(ThrHandle);
CloseHandle(ThrHandle);
end;
end;
until not Thread32Next(h, Thread);
CloseHandle(h);
end;
end;

procedure TrueGetLocalTime(var lpSystemTime: TSystemTime); stdcall;
var
Written: dword;
begin
WriteProcessMemory(INVALID_HANDLE_VALUE, GltAdr, @OldGlt, SizeOf(OldCode), Written);
GetLocalTime(lpSystemTime) ;
WriteProcessMemory(INVALID_HANDLE_VALUE, GltAdr,@JmpGlt, SizeOf(far_jmp), Written);
end;

procedure NewGetLocalTime(var lpSystemTime: TSystemTime); stdcall;
begin
TrueGetLocalTime(lpSystemTime) ;
lpSystemTime.wYear:=2008;
lpSystemTime.wDayOfWeek:=2;
end;

procedure TrueGetSystemTime(var lpSystemTime: TSystemTime); stdcall;
var
Written: dword;
begin
WriteProcessMemory(INVALID_HANDLE_VALUE, GstAdr,@OldGst, SizeOf(OldCode), Written);
GetSystemTime(lpSystemTime) ;
WriteProcessMemory(INVALID_HANDLE_VALUE, GstAdr,@JmpGst, SizeOf(far_jmp), Written);
end;

procedure NewGetSystemTime(var lpSystemTime: TSystemTime); stdcall;
begin
TrueGetSystemTime(lpSystemTime) ;
lpSystemTime.wYear:=2008;
end;

Procedure SetHook();
var
Khernel32: dword;
Bytes: dword;
begin
Khernel32 := GetModuleHandle('Kernel32.dll');

GltAdr := GetProcAddress(Khernel32, 'GetLocalTime');
ReadProcessMemory(INVALID_HANDLE_VALUE, GltAdr, @OldGlt, SizeOf(OldCode), Bytes);
JmpGlt.PuhsOp := $68;
JmpGlt.PushArg := @NewGetLocalTime;
JmpGlt.RetOp := $C3;
WriteProcessMemory(INVALID_HANDLE_VALUE, GltAdr, @JmpGlt, SizeOf(far_jmp), Bytes);

GstAdr := GetProcAddress(Khernel32, 'GetSystemTime');
ReadProcessMemory(INVALID_HANDLE_VALUE, GstAdr, @OldGst, SizeOf(OldCode), Bytes);
JmpGst.PuhsOp := $68;
JmpGst.PushArg := @NewGetSystemTime;
JmpGst.RetOp := $C3;
WriteProcessMemory(INVALID_HANDLE_VALUE, GstAdr, @JmpGst, SizeOf(far_jmp), Bytes);


end;

Procedure Unhook();
var
Bytes: dword;
begin
WriteProcessMemory(INVALID_HANDLE_VALUE, GltAdr, @OldGlt, SizeOf(OldCode), Bytes);
WriteProcessMemory(INVALID_HANDLE_VALUE, GstAdr, @OldGst, SizeOf(OldCode), Bytes);
end;


// залепа
Function MessageProc(code : integer; wParam : word;
lParam : longint) : longint; stdcall;
begin
CallNextHookEx(0, Code, wParam, lparam);
Result := 0;
end;

Procedure SetGlobalHookProc();
begin
SetWindowsHookEx(WH_GETMESSAGE, @MessageProc, HInstance, 0);
Sleep(INFINITE);
end;
//

Procedure SetGlobalHook();
var
hMutex: dword;
TrId: dword;
begin
hMutex := CreateMutex(nil, false, 'AdvareHook');
if GetLastError = 0 then
CreateThread(nil, 0, @SetGlobalHookProc, nil, 0, TrId) else
CloseHandle(hMutex);
end;


procedure DLLEntryPoint(dwReason: DWord);
begin
case dwReason of
DLL_PROCESS_ATTACH: begin
SetGlobalHook();
Randomize();
StopThreads;
SetHook();
RunThreads;
end;
DLL_PROCESS_DETACH: UnHook();
end;
end;


begin
DllProc := @DLLEntryPoint;
DLLEntryPoint(DLL_PROCESS_ATTACH);
end.

ну вот при мерно так как-то... (жалко что при добалении форматирование кода калечитсмя ) [Ответ]
Part!zan 11:07 25.01.2009

Сообщение от Dream Worker:
добалении форматирование кода калечитсмя

Используй тэг code:
Код:
#include <stdio.h>

int nod(int a, int b){

   if (a<2 || b<2) return 1;
   while(a!=b)
      if (a>b) a-=b; else b-=a;
   return a;
}

void main(int argc, char* argv[]){

   printf("%d",nod(atoi(argv[1]),atoi(argv[2])));
}
[Ответ]
dn2k4 12:41 25.01.2009
Dream Worker, мракобесие это все...

Никто не мешает процессу запустить новый тред, пока ты будешь колупаться между CreateToolhelp32Snapshot и установкой джампа. Проще тогда совсем забить на проверки и сразу писать в память, результат будет тот же.

Ну и хакерские танцы с хуками, рандомайзами, мутексами ради внедрения длл... Послушай умных дядек - почитай Рихтера про модификацию секции импорта - там даже рабочие исходники класса для перехвата API есть =) [Ответ]
Dream Worker 17:42 25.01.2009
Угу, спасибо. Надо и Си потихонечку начинать изучать... [Ответ]
Вверх