|
|
| Посл.отвђт | Сообщенiе |
|
|
Дата: Дек 2, 2003 19:22:16 Требуется найти в PE файле строку байт вида: BE 00 00 00 00 8B 95 00 00 00 00 03 F2 8B 46 где на месте нулей могут быть любые байты, найти конкретно одну такую строку не проблема, но если таких строк много, хотелось бы иметь процедуру, которая бы получала скан-строку и пределы в которых искать, а на выходе бы выдавала адрес первого байта строки, ну и ноль понятное дело в случае неудачи. Кто-нибудь писал такое?, какой может быть алгоритм у такой процедуры? Любые предложения приветствуются. |
|
|
Дата: Дек 2, 2003 19:34:13 Asterix Ну так ищешь BE, прибавляешь к счетчику 5, сравниваешь с 8B 95 и т.д. Потом повторяешь снова. В чем проблема то? Если я чего-то не понял поправь. |
|
|
Дата: Дек 2, 2003 19:44:11 hello_world А если последовательность будет другая? Хранить можно это в виде структуры, которая содержит основную строку, и количество нулей между какими-нибудь символами. а следом массив структур с длиной и смещениями этих нулей, например так: str db 0BEh, 8Bh, 95h, 03h, 0F2h, 8Bh, 46h seq struct str dd ? null_entries dd ? seq ends null_entry struct offset dd ? len dd ? null_entry ends короче в памяти всё это дело будет выглядеть так: seq1 dd offset str, 2 ;структура seq dd 1, 4 ;первая структура null_entry dd 3, 4 ;вторая структура ну а ищешь циклом с двумя указателями - до первого вхождения нулей, затем прибавляешь к указателю на содержимое PE файла длину нулей и ищешь данные между первым и вторым вхождением нулей, и.т.д. |
|
|
Дата: Дек 2, 2003 20:13:19 Asterix Я тебе самое классное решение предложу. Такое как в PE Sniffer, если NEOx когда-нибудь разродится переписать по моему примеру. Называется - регулярные выражения! Лови:
#include <windows.h>
#include <stdio.h>
#include "pcre.h" /*сгружай портированную версию с pcre.org*/
/*пример написан по мотивам pcredemo.c*/
#define OVECCOUNT 90 /* согласно требованиям автора должно делиться на 3 */
/*
1. Загрузить все функции
2. Спроецировать файл
3. Скомпилировать регулярное выражение
4. По принципу FindFileFirst/FindFileNext достать его.
*/
int main(void)
{
HMODULE hpcre = 0;
HANDLE hfile = 0, hmapfile = 0;
LPVOID lpvMem = 0;
/*PCRE stuff*/
pcre *re = 0;
char pattern[] = "\x8B\x1E\x83\xEE\xFC"; //UPX - именно шестнадцатеричные!
const char *error = 0;
int erroffset = 0;
int ovector[OVECCOUNT];
int subject_length = 0;
int rc = 0;
/*pointers to PCRE functions*/
pcre *(*pcre_compile)(const char *pattern, int options,
const char **errptr, int *erroffset,
const unsigned char *tableptr);
int (*pcre_exec) (const pcre *code, const pcre_extra *extra,
const char *subject, int length, int startoffset,
int options, int *ovector, int ovecsize);
/******************************************************************** /
if(!(hpcre = LoadLibraryA("pcre.dll")))
return -1;
if(!(*(DWORD *)&pcre_compile = (DWORD)GetProcAddress(hpcre, "pcre_compile")))
return -2;
if(!(*(DWORD *)&pcre_exec = (DWORD) GetProcAddress(hpcre, "pcre_exec")))
return -3;
hfile = CreateFile("calc.upx.exe", GENERIC_ALL, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
if (hfile == INVALID_HANDLE_VALUE)
return -4;
subject_length = (int) GetFileSize (hfile, 0);
hmapfile = CreateFileMapping(hfile, 0, PAGE_READWRITE, 0, 0, 0);
lpvMem = MapViewOfFile(hmapfile, FILE_MAP_ALL_ACCESS, 0, 0, 0);
/*не с lpvMem, а с секций! - незачем прогонять через заголовок! - поправь*/
re = pcre_compile(
pattern, /* последовательность для поиска - бинарные байты - БЕЗ ДВОИЧНЫХ НУЛЕЙ!!!! */
/*двоичные нули ты заранее можешь заменять регулярным выражением типа один символ один раз*/
0, /* default options */
&error, /* for error message */
&erroffset, /* for error offset */
NULL); /* use default character tables */
/* Compilation failed: print the error message and exit */
if (!re)
{
printf("PCRE compilation failed at offset %d: %s\n", erroffset, error);
return -5;
}
/*это найдет сигнатуру ТОЛЬКО РАЗ! Все остальные разы будем искать ниже*/
rc = pcre_exec(
/*заметь, файл УЖЕ МОЖЕТ содержать двоичные нули! - см. telock.exe - он обрабатывается корректно*/
re, /* скомпилированное выражение из pattern*/
NULL, /* no extra data - we didn't study the pattern */
(char*) lpvMem, /* the subject string - lpvMem from CreateFileMapping*/
subject_length, /* the length of the subject - from GetFileSize*/
0, /* start at offset 0 in the subject */
0, /* default options */
ovector, /* output vector for substring information */
OVECCOUNT); /* number of elements in the output vector */
CloseHandle(hfile);
CloseHandle(hmapfile);
/* Matching failed: handle error cases */
if (rc < 0)
{
switch(rc)
{
case PCRE_ERROR_NOMATCH: printf("No match\n");
break;
default: printf("Matching error %d\n", rc);
break;
}
UnmapViewOfFile(lpvMem);
return -6;
}
/* Match succeded */
printf("\nMatch succeeded at offset %d\n", ovector[0]); //--> test for PE section, etc...
/*теперь пошли искать все остальные вхождения*/
for (;;)
{
int options = 0; /* Normally no options */
int start_offset = ovector[1]; /* Start at end of previous match */
/* If the previous match was for an empty string, we are finished if we are
at the end of the subject. Otherwise, arrange to run another match at the
same point to see if a non-empty match can be found. */
if (ovector[0] == ovector[1])
{
if (ovector[0] == subject_length) break;
options = PCRE_NOTEMPTY | PCRE_ANCHORED;
}
/* Run the next matching operation */
rc = pcre_exec(
re, /* the compiled pattern */
NULL, /* no extra data - we didn't study the pattern */
(char*) lpvMem, /* the subject string */
subject_length, /* the length of the subject */
start_offset, /* starting offset in the subject */
0, /* options */
ovector, /* output vector for substring information */
OVECCOUNT); /* number of elements in the output vector */
if (rc == PCRE_ERROR_NOMATCH) /*в данном конкретном случае - это не ошибка - см. pcredemo.c*/
{
if (options == 0) break;
ovector[1] = start_offset + 1;
continue;
}
/* однако, если в rc НЕ -1 - значит, ошибка серьезная*/
if (rc < 0)
{
printf("Matching error %d\n", rc);
UnmapViewOfFile(lpvMem);
return -7;
}
/* Match succeded */
printf("\nMatch succeeded again at offset %d\n", ovector[0]);
/* The match succeeded, but the output vector wasn't big enough. */
if (rc == 0)
{
rc = OVECCOUNT/3;
printf("ovector only has room for %d captured substrings\n", rc - 1);
}
}
UnmapViewOfFile(lpvMem);
return -8;
}
|
|
|
Дата: Дек 2, 2003 20:14:28 hello_world Ну ты конечно не понял :-) Я знаю как искать скан-строку в файле, но мне хотелось иметь более универсальный вариант, помоему я в своём посте вполне понятно об этом написал. dragon Это мне нужно обдумать ;-). Спасибо. |
|
|
Дата: Дек 2, 2003 20:15:47 Ух, volodya!, жалко только что на C, будем разбираться ;-) |
|
|
Дата: Дек 2, 2003 20:45:14 Сделаю поправочку, файл у меня уже в памяти, стоит под отладчиком(моим), доступ к нему имею через ReadProcessMemory, поэтому маппить ничего не требуется. |
|
|
Дата: Дек 2, 2003 20:54:08 Asterix Если что-то неясно - спрашивай. Синтаксис твоего HLL достаточно близок, поэтому %80 понять ты сможешь. Если чего-то не догонишь, тогда спрашивай. |
|
|
Дата: Дек 3, 2003 01:08:12 · Поправил: hello_world Asterix Исправляюсь :) Вот функцию написал: .data nesovp db "не " sovp db "совпали!",0 scan db 0aah,0,0,0,0bbh,0,0cch file db 1,2,3,4,0aah,5,6,7,0bbh,8,0cch,9,10,11,12,13,14,15 .code start: push sizeof scan push offset scan push offset file push sizeof file call ScanSearch .if eax==0 invoke MessageBox,0,offset sovp,offset sovp,0 .else invoke MessageBox,0,offset nesovp,offset nesovp,0 .endif invoke ExitProcess,0 ;######################################################### ScanSearch: ; длина 51 байт !!! :) ;Usage: ; ;push размер сканстроки ;push offset сканстроки ;push offset файла ;push размер файла ;call ScanSearch ; ;Return: ; ;eax == 0 - found ;edi - offset dec dword ptr [esp + 8] mov eax,[esp + 16] add esp,4 pop edx sub edx,eax inc edx inc edx ___search: dec edx test edx,edx jz ___exit pop edi pop esi pop ecx inc edi push ecx push esi push edi ___lodsb: lodsb test al,al jnz ___cmpsb inc edi loop ___lodsb jcxz ___exit ___cmpsb: dec esi cmpsb jnz ___search loop ___lodsb ___exit: mov eax,ecx sub esp,8 ret ;######################################################### end start ЗЫ Я знаю что это извращение, но можно уложиться меньше чем в 51 байт. Если хочешь пиши, а у меня уже бошка болит :) |
|
|
Дата: Дек 3, 2003 08:24:14 hello_world Что-то уж больно коротко ;-), ладно я потом подумаю над всем этим и напишу, у меня в голове тоже крутится идея только пока схватить её не могу ;-) |
|
|
Дата: Дек 3, 2003 13:06:34 Хе, а я тут вот че придумал... Можно сделать что-то типа компилятора кода для проверки скан-строки и генерить этот год в рантайме. Для BE 00 00 00 00 8B 95 00 00 00 00 03 F2 8B 46 скомпилим типа:
// Вход: esi - указатель на память
// Выход: eax=1 - скан-строка совпадает, 0 - не совпадает
xor eax,eax
cmp byte ptr [esi],0BEh
jne @exit
add esi,5
cmp byte ptr [esi],08Bh
jne @exit
inc esi
...
inc eax
@exit:
ret
З.Ы. можно обойтись без переходов за счет CMOVcc, но тогда придется проверять всю скан-строку целиком. Может быстрее получится, а может медленнее - проверять надо... |
|
|
Дата: Дек 3, 2003 13:11:08 ...а можно этот компилятор еще немного и прооптимизировать, типа для 2-х подряд идущих байтов использовать cmp word ptr [esi],xxxx, а для четырех cmp dword ptr [esi],xxxx... а для 16-и подключить SSE2 регистры... :)) |
|
|
Дата: Дек 3, 2003 18:44:52 Max По-моему вы все упрощаете задачу, на выходе нужно получить адрес первого байта такой скан-строки в файле и ноль в случае неудачи, причём функция должна быть универсальной, т.е. если я задам другую скан-строку то она должна её также корректно искать. |
|
|
Дата: Дек 3, 2003 18:55:12 Я предложил универсальное решение. Скорость, правда, низковата... |
|
|
Дата: Дек 3, 2003 19:06:33 volodya Я так понимаю твой пример использует pcre.dll, если так то это плохо. |
|
Powered by miniBB 1.6 © 2001-2002
Время загрузки страницы (сек.): 0.061 |