;######################################################################### ;Процедура GetAPIs ;Получение адресов всех требуемых API-функций ;Вход: В edi указатель на массив ASCIIZ строк имен функций ; В ebx - смещение массива двойных слов которые заполняет функция ; В esi - база kernel32.dll ; В ecx - адрес функции GetProcAddress ;Выход:заполняются соответствующие поля ;######################################################################### GetAPIs proc Number:DWORD pushad mov eax,ecx mov ecx,Number NextFunc: push eax push esi push edi push ebx push ecx push edi;имя функции push esi;база kernel32 call eax;вызов GetProcAddress pop ecx pop ebx pop edi pop esi mov dword ptr [ebx],eax;помещаем адрес функции в переменную pop eax add ebx,4;следующая переменная push ecx;сохраняем счетчик mov ecx,30;для цепочечной команды push eax mov al,0;ищем 0 repne scasb pop eax pop ecx loop NextFunc popad ret GetAPIs endp ;######################################################################### ;Конец процедуры GetAPIs ;######################################################################### ;######################################################################### ;Процедура GetGetProcAddress ;Поиск адреса внутри kernel32.dll ;Вход: в стек кладется смещение имени "GetProcAddress" ; ebx - база kernel32.dll ;Выход:В eax - адрес функции GetProcAddress ;######################################################################### GetGetProcAddress proc NameFunc:DWORD pushad;сохраняем регистры mov esi,ebx assume esi:ptr IMAGE_DOS_HEADER add esi,[esi].e_lfanew;в esi - заголовок PE assume esi:ptr IMAGE_NT_HEADERS lea esi,[esi].OptionalHeader;в esi - адрес опционального заголовка assume esi:ptr IMAGE_OPTIONAL_HEADER lea esi,[esi].DataDirectory;в esi - адрес DataDirectory mov esi,dword ptr [esi] add esi,ebx;в esi - структура IMAGE_EXPORT_DIRECTORY push esi assume esi:ptr IMAGE_EXPORT_DIRECTORY mov esi,[esi].AddressOfNames add esi,ebx;в esi - массив имен функций xor edx,edx;в edx - храним индекс mov eax,esi mov esi,dword ptr [esi] NextName:;поиск следующего имени функции add esi,ebx mov edi,NameFunc mov ecx,14;количество байт в "GetProcAddress" cld repe cmpsb .IF ecx==0;нашли имя jmp GetAddr .ENDIF inc edx add eax,4 mov esi,dword ptr [eax] jmp NextName GetAddr:;если нашли "GetProcAddress" pop esi mov edi,esi mov esi,[esi].AddressOfNameOrdinals add esi,ebx;в esi - массив слов с индесками mov dx,word ptr [esi][edx*2] assume edi:ptr IMAGE_EXPORT_DIRECTORY sub edx,[edi].nBase;вычитаем начальный ординал inc edx;т.к. начальный ординал начинается с 1 mov esi,[edi].AddressOfFunctions add esi,ebx;в esi - массив адресов функций mov eax,dword ptr [esi][edx*4] add eax,ebx;в eax - адрес функции GetProcAddress mov NameFunc,eax popad;восстанавливаем регистры mov eax,NameFunc ret GetGetProcAddress endp ;######################################################################### ;Конец процедуры GetGetProcAddress ;######################################################################### ;######################################################################### ;Процедура GetKernelImport ;Поиск адреса внутри kernel32.dll ;Вход: ничего ;Выход:В eax - адрес внутри kernel32.dll ;######################################################################### GetKernelImport proc push esi push ebx push edi call x x: mov esi,dword ptr [esp];в esi - смещение данной команды add esp,4;выравниваем стек and esi,0FFFF0000h;используем гранулярность y: call ValidPE;начало EXE-файла? .IF eax==0;если нет, то ищем дальше sub esi,010000h jmp y .ENDIF mov ebx,esi;в ebx теперь будем хранить базу assume esi:ptr IMAGE_DOS_HEADER add esi,[esi].e_lfanew;в esi - заголовок PE assume esi:ptr IMAGE_NT_HEADERS lea esi,[esi].OptionalHeader;в esi - адрес опционального заголовка assume esi:ptr IMAGE_OPTIONAL_HEADER lea esi,[esi].DataDirectory;в esi - адрес DataDirectory add esi,8;в esi - элемент 1 в DataDirectory mov eax,ebx add eax,dword ptr [esi];в eax - смещение таблицы импорта mov esi,eax assume esi:ptr IMAGE_IMPORT_DESCRIPTOR NextDLL: mov edi,[esi].Name1 add edi,ebx .IF DWORD PTR [edi]=="NREK";черт, мы могли бы написать так: .IF TBYTE PTR [edi]=="LLD.LENREK", но нас сдерживает формат машинной команды Intel в которой константа может быть не более 4 байт ;нашли запись о kernel32!!! mov edi,[esi].FirstThunk add edi,ebx;в edi - VA массива IMAGE_THUNK_DATA mov eax,dword ptr [edi];в eax адрес какой-то из функций kernel32.dll pop edi pop ebx pop esi ret .ENDIF add esi,sizeof IMAGE_IMPORT_DESCRIPTOR jmp NextDLL GetKernelImport endp ;######################################################################### ;Конец процедуры GetKernelImport ;######################################################################### ;######################################################################### ;Процедура GetKernelSEH ;Поиск адрес внутри kernel32.dll ;Вход: ничего ;Выход:В eax - адрес внутри kernel32.dll ;######################################################################### GetKernelSEH proc assume fs:flat;для масма обязательно. по умолчанию assume fs:err mov eax,dword ptr fs:[0];в eax - указатель на структуру ERR NextElem: cmp dword ptr [eax],-1;последний элемент je Yes mov eax,dword ptr [eax] jmp NextElem Yes:;если пришли к последнему элементу mov eax,[eax+4] ret GetKernelSEH endp ;######################################################################### ;Конец процедуры GetKernelSEH ;######################################################################### ;######################################################################### ;Процедура GetBase ;Поиск базы исполняемого файла, если есть адрес где-то внутри него ;Вход: В esi - адрес внутри файла в памяти ;Выход:В eax - база PE-файла ;Заметки:обычно процедура используется с спроецируемыми файлами в память ;######################################################################### GetBase proc LOCAL Base:DWORD;чтобы не изменять контекст по договоренности push esi;сохраняем все регистры, которые используются push ecx pushf;сохраняем регистр флагов and esi,0FFFF0000H;гранулярность выделения памяти mov ecx,6;счетчик страниц NextPage:;проверка очередной страницы call ValidPE .IF eax==1 mov Base,esi popf pop ecx pop esi mov eax,Base ret .ENDIF sub esi,10000H loop NextPage popf;восстанавливаем значения флагов pop ecx pop esi;восстанавливаем значения регистров mov eax,FALSE;не нашли базу :( ret GetBase endp ;######################################################################### ;Конец процедуры GetBase ;######################################################################### ;######################################################################### ;Процедура ValidPE ;Проверка правильный ли PE-файл ;Вход: В esi - адрес файла в памяти ;Выход:если файл правильный, то eax=1, иначе eax=0 ;Заметки:обычно процедура используется с спроецируемыми файлами в память ;######################################################################### ValidPE proc push esi;сохраняем все регистры pushf;сохраняем регистр флагов .IF WORD ptr [esi]=="ZM" assume esi:ptr IMAGE_DOS_HEADER;указание компилятору, что в esi указатель на IMAGE_DOS_HEADER add esi,[esi].e_lfanew;переход к PE заголовку .IF WORD PTR [esi]=="EP" popf;восстанавливаем значения флагов pop esi;восстанавливаем значения регистров mov eax,TRUE ret .ENDIF .ENDIF popf;восстанавливаем значения флагов pop esi;восстанавливаем значения регистров mov eax,FALSE ret ValidPE endp ;######################################################################### ;Конец процедуры ValidPE ;#########################################################################