Форум: "Потрепаться";
Текущий архив: 2003.08.14;
Скачать: [xml.tar.bz2];
ВнизПерехват API Найти похожие ветки
← →
Spawn (2003-06-03 22:00) [0]Пробую делать перехват вызовов WinSock API, а именно функции recv. Но что то, используемый мною класс ее ни как не меняет. Внедряюсь в чужое АП при помощи хуков - внедрение проходит успешно, поскольку проверяю наличие библиотеки winsock в процессе через GetModuleHandle.
Вот утсановка хука( часть DLL):
...
const
wsocket="wsock32.dll";
WM_SETSOCKETHOOK=WM_USER+100;
SpecificId=65535;
type
THook_Recv=function(s: TSocket; var Buf; len, flags: Integer): Integer; stdcall;
var
OldRecv:THook_Recv=nil;
PeImportHooks:=TJclPeMapImgHooks;
Hooked:Boolean=False;
function Hook_Recv(s: TSocket; var Buf; len, flags: Integer): Integer; stdcall;
var
CopyData:TCOPYDATASTRUCT;
begin
//пересылка данных в компонент обработки
Result:=OldRecv(s,Buf,len,flags);
end;
function SetSocketHook:Boolean;
begin
Result:=False;
PeImportHooks:=nil;
PeImportHooks:=TJclPeMapImgHooks.Create;
if PeImportHooks.HookImport(Pointer(HInstance), wsocket, "recv",
@Hook_Recv, @OldRecv) then
begin
Result:=True;
ShowMessage("Set Hook");
end
else
begin
ShowMessage("Error Set Hook);
PeImportHooks.Free;
end;
end;
function MsgProc(Code: integer; WParam: word; LParam: Longint): Longint; stdcall;
var
msg: PMSG;
begin
if Code >= 0 then
begin
Result := 0;
Msg := Pointer(LParam);
if (Msg.message=WM_SETSOCKETHOOK) and (Msg.wParam=SpecificId) then
begin
if SetSocketHook then
Hooked:=True;
end;
end
else
Result := CallNextHookEx(HookHandle, code, WParam, LParam);
end;
procedure SetHook;export;stdcall;
begin
HookHandle:=SetWindowsHookEx(WH_GETMESSAGE, @MsgProc, HInstance, 0);
end;
...
Я заглянул в класс подмены функции таблицы импорта, но там все ок - ошибок не было. Причины была в том, что класс, видимо, не нашел этой функции в таблице импорта, поскольку в цикле просморта я подставлял ShowMessage но нахождения не было:
ImportDesc := PImageImportDescriptor(DWORD(Base) + ImportDir.VirtualAddress);
while ImportDesc^.Name <> 0 do
begin
CurrName := PChar(Base) + ImportDesc^.Name;
if StrIComp(CurrName, PChar(ModuleName)) = 0 then
begin
ImportEntry := PImageThunkData(DWORD(Base) + ImportDesc^.FirstThunk);
while ImportEntry^.Function_ <> 0 do
begin
if IsThunked then
begin
ImportThunk := PWin9xDebugThunk(ImportEntry^.Function_);
FoundProc := IsWin9xDebugThunk(ImportThunk) and (ImportThunk^.Addr = FromProcDebugThunk^.Addr);
end
else
FoundProc := Pointer(ImportEntry^.Function_) = FromProc;
if FoundProc and not IsBadStringPtr(Pointer(ImportEntry^.Function_), 4) then
begin
Pointer(ImportEntry^.Function_) := ToProc; ShowMessage("Proc Finded");
Result := True;
end;
Inc(ImportEntry);
end;
end;
Inc(ImportDesc);
end;
. Продезассемблировав нужную мне прогу при помощи IDA Pro, я увидел там вот это:
.idata:004E435C extrn __imp_recv:dword; DATA XREF: recvr
.idata:004E435C ; Receive data from a socket
Почему в заголовке файла она хранится как __imp_recv?
Подскажите пожалста в чем может быть ошибка подмены импорта.
При изучении класса подмены таблицы импорта оказалось, что при поиске необходимой библиотеки (wsock32.dll) в таблице ее не оказалось, т.е код, находящийся за
if StrIComp(CurrName, PChar(ModuleName)) = 0 then
begin
ни когда не выполняется.
Хотя в этой же ДЛЛ я вызываю GetModuleHandle("wsock32.dll") - все ок. И вызываю GetPorcAddress(wsock32Handle,"recv") - тоже все ок. Так в чем же может быть дело? Заранее благодарен за ответ.
← →
Digitman (2003-06-04 12:13) [1]Возможно, ф-ция импортируется по ординалу
У тебя же, очевидно, поиск по ординалу не предусмотрен
см. условие "... and not IsBadStringPtr() ..."
попробуй воспользоваться вот этими ф-циями для модификации таблиц экспорта-импорта с целью подмены точки входа
см. в 1-ю очередь SetDLLProcAddress()
правда, адаптирована она для NT-платформ, но можно доработать и для Win9x в части перечисления модулей в ВАП вызывающенго процесса на предмет модификации их таблиц импорта, если модули обращаются к интересующей перехватываемой ф-ции
function GetDLLProcAddress(lpExpModuleName, lpProcName: PChar): Pointer;
var
hExporter: THandle;
pOptHdr: PImageOptionalHeader;
pExpDir: PImageExportDirectory;
pName: PChar;
pdwNamePtr, pdwEntryPoint: PDWord;
pwOrdinalPtr: PWord;
i, nOrdinal: DWord;
begin
Result := nil;
hExporter := GetModuleHandle(lpExpModuleName);
if hExporter = 0 then
Exit;
pOptHdr := PImageOptionalHeader(hExporter + PImageDosHeader(hExporter)._lfanew + SIZE_OF_NT_SIGNATURE + IMAGE_SIZEOF_FILE_HEADER);
if (pOptHdr.NumberOfRvaAndSizes < 16) or (pOptHdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size = 0) then
Exit;
pExpDir := PImageExportDirectory(hExporter + pOptHdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
pdwEntryPoint := nil;
pwOrdinalPtr := PWord(hExporter + DWord(pExpDir.AddressOfNameOrdinals));
if HiWord(DWord(lpProcName)) = 0 then
begin
nOrdinal := LoWord(DWord(lpProcName)) - pExpDir.Base;
if (nOrdinal < pExpDir.NumberOfFunctions) then
pdwEntryPoint := PDWord(hExporter + DWord(pExpDir.AddressOfFunctions) + nOrdinal * SizeOf(PDWord));
end
else
begin
pdwNamePtr := PDWord(hExporter + DWord(pExpDir.AddressOfNames)) ;
for i := 0 to pExpDir.NumberOfNames - 1 do
begin
pName := PChar(PDWord(hExporter + PDword(pdwNamePtr)^));
if lstrcmp(pName,lpProcName) = 0 then
begin
nOrdinal := pwOrdinalPtr^;
pdwEntryPoint := PDWord(hExporter + DWord(pExpDir.AddressOfFunctions) + nOrdinal * SizeOf(PDWord));
break;
end
else
begin
Inc(pdwNamePtr);
Inc(pwOrdinalPtr);
end
end;
end;
if Assigned(pdwEntryPoint) and (pdwEntryPoint^ <> 0) then
( hExporter + pdwEntryPoint^)Возможно, ф-ция импортируется по ординалу
У тебя же, очевидно, поиск по ординалу не предусмотрен
см. условие "... and not IsBadStringPtr() ..."
попробуй воспользоваться вот этими ф-циями для модификации таблиц экспорта-импорта с целью подмены точки входа
см. в 1-ю очередь SetDLLProcAddress()
правда, адаптирована она для NT-платформ, но можно доработать и для Win9x в части перечисления модулей в ВАП вызывающенго процесса на предмет модификации их таблиц импорта, если модули обращаются к интересующей перехватываемой ф-ции
function GetDLLProcAddress(lpExpModuleName, lpProcName: PChar): Pointer;
var
hExporter: THandle;
pOptHdr: PImageOptionalHeader;
pExpDir: PImageExportDirectory;
pName: PChar;
pdwNamePtr, pdwEntryPoint: PDWord;
pwOrdinalPtr: PWord;
i, nOrdinal: DWord;
begin
Result := nil;
hExporter := GetModuleHandle(lpExpModuleName);
if hExporter = 0 then
Exit;
pOptHdr := PImageOptionalHeader(hExporter + PImageDosHeader(hExporter)._lfanew + SIZE_OF_NT_SIGNATURE + IMAGE_SIZEOF_FILE_HEADER);
if (pOptHdr.NumberOfRvaAndSizes < 16) or (pOptHdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size = 0) then
Exit;
pExpDir := PImageExportDirectory(hExporter + pOptHdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
pdwEntryPoint := nil;
pwOrdinalPtr := PWord(hExporter + DWord(pExpDir.AddressOfNameOrdinals));
if HiWord(DWord(lpProcName)) = 0 then
begin
nOrdinal := LoWord(DWord(lpProcName)) - pExpDir.Base;
if (nOrdinal < pExpDir.NumberOfFunctions) then
pdwEntryPoint := PDWord(hExporter + DWord(pExpDir.AddressOfFunctions) + nOrdinal * SizeOf(PDWord));
end
else
begin
pdwNamePtr := PDWord(hExporter + DWord(pExpDir.AddressOfNames)) ;
for i := 0 to pExpDir.NumberOfNames - 1 do
begin
pName := PChar(PDWord(hExporter + PDword(pdwNamePtr)^));
if lstrcmp(pName,lpProcName) = 0 then
begin
nOrdinal := pwOrdinalPtr^;
pdwEntryPoint := PDWord(hExporter + DWord(pExpDir.AddressOfFunctions) + nOrdinal * SizeOf(PDWord));
break;
end
else
begin
Inc(pdwNamePtr);
Inc(pwOrdinalPtr);
end
end;
end;
if Assigned(pdwEntryPoint) and (pdwEntryPoint^ <> 0) then
Result := Pointer(hExporter + pdwEntryPoint^);
end;
← →
Digitman (2003-06-04 12:14) [2]
// lpExpModuleName - имя модуля, например, "wsock32.dll"
// lpProcName - имя или ординал экспортируемой модулем ф-ции, например, "recv" (имя) или 16 (ее ординал)
// адрес новой точки входа, например, @Hook_Recv
// Result - старая (оригинальная) точка входа до подмены
function SetDLLProcAddress(lpExpModuleName, lpProcName: PChar; pProcAddr: Pointer): Pointer;
var
hProcess: THandle;
hExporter, hImporter, hModule: THandle;
pOptHdr: PImageOptionalHeader;
pExpDir: PImageExportDirectory;
pImpDir: PImageImportDescriptor;
pIATEntry: PImageThunkData;
pName: PChar;
pdwNamePtr, pdwEntryPoint: PDWord;
pwOrdinalPtr: PWord;
i, dwDirSize, nOrdinal, dwProtect, dwNewProcAddrRVA: DWord;
peb: PPeb;
pLdrData : PPEB_LDR_DATA;
pLoadOrderList : PPLIST_ENTRY;
pInLoadModuleEntry: PModuleEntry;
pModuleNfo: PModuleInfo;
begin
Result := nil;
// получение хэндла экспортирующего модуля
hExporter := GetModuleHandle(lpExpModuleName);
//если целевой модуль на данный момент не загружен - конец
if hExporter = 0 then
Exit;
// ограничение на запись nil при подмене точки входа
if not Assigned(pProcAddr) then
Exit;
// адрес актуален/доступен в текущем ВАП ? если - да, в каком модуле в тек.процесса находится ф-ция - обработчик перехвата ?
hModule := FindHInstance(pProcAddr);
if hModule = 0 then
Exit;
// получение адреса ф-ции lpProcName в экспортирующем (целевом) модуле
pOptHdr := PImageOptionalHeader(hExporter + PImageDosHeader(hExporter)._lfanew + SIZE_OF_NT_SIGNATURE + IMAGE_SIZEOF_FILE_HEADER);
dwDirSize := pOptHdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size;
if (pOptHdr.NumberOfRvaAndSizes < 16) or (dwDirSize = 0) then
Exit;
pExpDir := PImageExportDirectory(hExporter + pOptHdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
pdwEntryPoint := nil;
pwOrdinalPtr := PWord(hExporter + DWord(pExpDir.AddressOfNameOrdinals));
if HiWord(DWord(lpProcName)) = 0 then
begin
nOrdinal := LoWord(DWord(lpProcName)) - pExpDir.Base;
if (nOrdinal < pExpDir.NumberOfFunctions) then
pdwEntryPoint := PDWord(hExporter + DWord(pExpDir.AddressOfFunctions) + nOrdinal * SizeOf(PDWord));
end
else
begin
pdwNamePtr := PDWord(hExporter + DWord(pExpDir.AddressOfNames)) ;
for i := 0 to pExpDir.NumberOfNames - 1 do
begin
pName := PChar(PDWord(hExporter + PDword(pdwNamePtr)^));
if lstrcmp(pName,lpProcName) = 0 then
begin
nOrdinal := pwOrdinalPtr^;
pdwEntryPoint := PDWord(hExporter + DWord(pExpDir.AddressOfFunctions) + nOrdinal * SizeOf(PDWord));
Inc(nOrdinal, pExpDir.Base);
break;
end
else
begin
Inc(pdwNamePtr);
Inc(pwOrdinalPtr);
end
end;
end;
if not Assigned(pdwEntryPoint) or (pdwEntryPoint^ = 0) then
Exit;
// точка входа найдена
Result := Pointer(hExporter + pdwEntryPoint^);
// расчет отн.смещения новой точки входа отн-но базы целевого модуля
dwNewProcAddrRVA := DWord(pProcAddr) - hExporter;
// модификация параметров защиты страницы, в которой находится таблица экспорта целевого модуля
hProcess := OpenProcess(PROCESS_VM_OPERATION, False, GetCurrentProcessId);
try
if VirtualProtectEx(hProcess, pExpDir, dwDirSize, PAGE_EXECUTE_WRITECOPY, dwProtect) then
try
pdwEntryPoint^ := dwNewProcAddrRVA;
finally
( hProcess, pExpDir, dwDirSize, dwProtect, dwProtect)
// lpExpModuleName - имя модуля, например, "wsock32.dll"
// lpProcName - имя или ординал экспортируемой модулем ф-ции, например, "recv" (имя) или 16 (ее ординал)
// адрес новой точки входа, например, @Hook_Recv
// Result - старая (оригинальная) точка входа до подмены
function SetDLLProcAddress(lpExpModuleName, lpProcName: PChar; pProcAddr: Pointer): Pointer;
var
hProcess: THandle;
hExporter, hImporter, hModule: THandle;
pOptHdr: PImageOptionalHeader;
pExpDir: PImageExportDirectory;
pImpDir: PImageImportDescriptor;
pIATEntry: PImageThunkData;
pName: PChar;
pdwNamePtr, pdwEntryPoint: PDWord;
pwOrdinalPtr: PWord;
i, dwDirSize, nOrdinal, dwProtect, dwNewProcAddrRVA: DWord;
peb: PPeb;
pLdrData : PPEB_LDR_DATA;
pLoadOrderList : PPLIST_ENTRY;
pInLoadModuleEntry: PModuleEntry;
pModuleNfo: PModuleInfo;
begin
Result := nil;
// получение хэндла экспортирующего модуля
hExporter := GetModuleHandle(lpExpModuleName);
//если целевой модуль на данный момент не загружен - конец
if hExporter = 0 then
Exit;
// ограничение на запись nil при подмене точки входа
if not Assigned(pProcAddr) then
Exit;
// адрес актуален/доступен в текущем ВАП ? если - да, в каком модуле в тек.процесса находится ф-ция - обработчик перехвата ?
hModule := FindHInstance(pProcAddr);
if hModule = 0 then
Exit;
// получение адреса ф-ции lpProcName в экспортирующем (целевом) модуле
pOptHdr := PImageOptionalHeader(hExporter + PImageDosHeader(hExporter)._lfanew + SIZE_OF_NT_SIGNATURE + IMAGE_SIZEOF_FILE_HEADER);
dwDirSize := pOptHdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size;
if (pOptHdr.NumberOfRvaAndSizes < 16) or (dwDirSize = 0) then
Exit;
pExpDir := PImageExportDirectory(hExporter + pOptHdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
pdwEntryPoint := nil;
pwOrdinalPtr := PWord(hExporter + DWord(pExpDir.AddressOfNameOrdinals));
if HiWord(DWord(lpProcName)) = 0 then
begin
nOrdinal := LoWord(DWord(lpProcName)) - pExpDir.Base;
if (nOrdinal < pExpDir.NumberOfFunctions) then
pdwEntryPoint := PDWord(hExporter + DWord(pExpDir.AddressOfFunctions) + nOrdinal * SizeOf(PDWord));
end
else
begin
pdwNamePtr := PDWord(hExporter + DWord(pExpDir.AddressOfNames)) ;
for i := 0 to pExpDir.NumberOfNames - 1 do
begin
pName := PChar(PDWord(hExporter + PDword(pdwNamePtr)^));
if lstrcmp(pName,lpProcName) = 0 then
begin
nOrdinal := pwOrdinalPtr^;
pdwEntryPoint := PDWord(hExporter + DWord(pExpDir.AddressOfFunctions) + nOrdinal * SizeOf(PDWord));
Inc(nOrdinal, pExpDir.Base);
break;
end
else
begin
Inc(pdwNamePtr);
Inc(pwOrdinalPtr);
end
end;
end;
if not Assigned(pdwEntryPoint) or (pdwEntryPoint^ = 0) then
Exit;
// точка входа найдена
Result := Pointer(hExporter + pdwEntryPoint^);
// расчет отн.смещения новой точки входа отн-но базы целевого модуля
dwNewProcAddrRVA := DWord(pProcAddr) - hExporter;
// модификация параметров защиты страницы, в которой находится таблица экспорта целевого модуля
hProcess := OpenProcess(PROCESS_VM_OPERATION, False, GetCurrentProcessId);
try
if VirtualProtectEx(hProcess, pExpDir, dwDirSize, PAGE_EXECUTE_WRITECOPY, dwProtect) then
try
pdwEntryPoint^ := dwNewProcAddrRVA;
finally
VirtualProtectEx(hProcess, pExpDir, dwDirSize, dwProtect, dwProtect);
end;
← →
Digitman (2003-06-04 12:15) [3]
// все ! с этого момента код.потоки процесса,
// динамически линкующие целевой модуль (LoadLibrary() + GetProcAddr()), вернут корректно настроенный новый адрес точки входа
// теперь сканируем список загруженных модулей тек.процесса и их таблиц импорта на предмет поиска записей об импорте целевой точки входа,
// найденной в целевом экспортирующем модуле lpExpModuleName
//(ищем и модифицируем данные об импорте, сформированные на этапе стат.линковки)
// получаем адрес блока окружения тек.процесса
peb := GetCurrentPEB; // mov eax, fs:[TTeb.Peb], NT-specific
// LockLoader(peb); // необязательная, но в ряде случаев желательная блокировка загрузчика
try
pLdrData := peb^.LdrData;
pLoadOrderList := @pLdrData.InLoadOrderModuleList;
pInLoadModuleEntry := PModuleEntry(pLoadOrderList^);
while PPListEntry(pInLoadModuleEntry) <> pLoadOrderList do
begin
pModuleNfo := @pInLoadModuleEntry.ModuleInfoData;
hImporter := THandle(pModuleNfo^.DllBase);
if hImporter <> hExporter then // пропуск эксп.модуля
begin
pOptHdr := PImageOptionalHeader(hImporter + PImageDosHeader(hImporter)._lfanew + SIZE_OF_NT_SIGNATURE + IMAGE_SIZEOF_FILE_HEADER);
if (pOptHdr.NumberOfRvaAndSizes = 16) then
begin
dwDirSize := pOptHdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size;
if dwDirSize > 0 then
begin
pImpDir := PImageImportDescriptor(hImporter + pOptHdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
while Assigned(PChar(pImpDir.RVAImportModuleName)) do
begin
if lstrcmpi(PChar(hImporter + pImpDir.RVAImportModuleName), lpExpModuleName) = 0 then
begin
pIATEntry := PImageThunkData(hImporter + DWord(pImpDir.RVAImportAddressTable));
while Assigned(pIATEntry.Func) do
begin
if pIATEntry.Func = Result then
begin
if VirtualProtectEx(hProcess, pIATEntry, SizeOf(pIATEntry), PAGE_EXECUTE_WRITECOPY, dwProtect) then
begin
pIATEntry.Func := pProcAddr;
VirtualProtectEx(hProcess, pIATEntry, SizeOf(pIATEntry), dwProtect, dwProtect);
end;
break;
end;
Inc(pIATEntry);
end;
end;
Inc(pImpDir);
end;
end;
end;
end;
pInLoadModuleEntry := PModuleEntry(pInLoadModuleEntry.InLoadOrderLinks.Flink);
end;
finally
// UnlockLoader(peb);
end;
finally
( hProcess)
// все ! с этого момента код.потоки процесса,
// динамически линкующие целевой модуль (LoadLibrary() + GetProcAddr()), вернут корректно настроенный новый адрес точки входа
// теперь сканируем список загруженных модулей тек.процесса и их таблиц импорта на предмет поиска записей об импорте целевой точки входа,
// найденной в целевом экспортирующем модуле lpExpModuleName
//(ищем и модифицируем данные об импорте, сформированные на этапе стат.линковки)
// получаем адрес блока окружения тек.процесса
peb := GetCurrentPEB; // mov eax, fs:[TTeb.Peb], NT-specific
// LockLoader(peb); // необязательная, но в ряде случаев желательная блокировка загрузчика
try
pLdrData := peb^.LdrData;
pLoadOrderList := @pLdrData.InLoadOrderModuleList;
pInLoadModuleEntry := PModuleEntry(pLoadOrderList^);
while PPListEntry(pInLoadModuleEntry) <> pLoadOrderList do
begin
pModuleNfo := @pInLoadModuleEntry.ModuleInfoData;
hImporter := THandle(pModuleNfo^.DllBase);
if hImporter <> hExporter then // пропуск эксп.модуля
begin
pOptHdr := PImageOptionalHeader(hImporter + PImageDosHeader(hImporter)._lfanew + SIZE_OF_NT_SIGNATURE + IMAGE_SIZEOF_FILE_HEADER);
if (pOptHdr.NumberOfRvaAndSizes = 16) then
begin
dwDirSize := pOptHdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size;
if dwDirSize > 0 then
begin
pImpDir := PImageImportDescriptor(hImporter + pOptHdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
while Assigned(PChar(pImpDir.RVAImportModuleName)) do
begin
if lstrcmpi(PChar(hImporter + pImpDir.RVAImportModuleName), lpExpModuleName) = 0 then
begin
pIATEntry := PImageThunkData(hImporter + DWord(pImpDir.RVAImportAddressTable));
while Assigned(pIATEntry.Func) do
begin
if pIATEntry.Func = Result then
begin
if VirtualProtectEx(hProcess, pIATEntry, SizeOf(pIATEntry), PAGE_EXECUTE_WRITECOPY, dwProtect) then
begin
pIATEntry.Func := pProcAddr;
VirtualProtectEx(hProcess, pIATEntry, SizeOf(pIATEntry), dwProtect, dwProtect);
end;
break;
end;
Inc(pIATEntry);
end;
end;
Inc(pImpDir);
end;
end;
end;
end;
pInLoadModuleEntry := PModuleEntry(pInLoadModuleEntry.InLoadOrderLinks.Flink);
end;
finally
// UnlockLoader(peb);
end;
finally
CloseHandle(hProcess);
end;
end;
p.s.
bold-строки в случае с Win9x следует заменить на алгоритм перечисления модулей в составе тек.процесса с использовпанием, например, соответствующих ToolHelp32-функций.
в ходе перечисления каждая while-итерация должна заполнить переменную hImporter хэндлом (читай - базовым адресом загрузки) очередного перечисляемого модуля перед тем как сканируется/модифицируется его таблица импорта
Страницы: 1 вся ветка
Форум: "Потрепаться";
Текущий архив: 2003.08.14;
Скачать: [xml.tar.bz2];
Память: 0.51 MB
Время: 0.005 c