Форум dkLab и Denwer
Здесь общаются Web-разработчики.
Генеральный спонсор:
Хостинг «Джино»

Получение адреса начала функции с определенным именем в теле EXE-файла. (Дмитрий Котеров)
Author Message
Дмитрий Котеров
Администратор



Joined: 10 Mar 2003
Posts: 13665
Карма: 411
   поощрить/наказать


PostPosted: Wed Nov 23, 2005 5:40 pm (написано за 2 минуты 40 секунд)
   Post subject: Получение адреса начала функции с определенным именем в теле EXE-файла.
Reply with quote

Вот, написал тут, первая версия. Вдруг пригодится кому...

Принимает на вход имя файла EXE или DLL, а также имя функции из секции EXPORT (т.е. имя функции, которую библиотека экспортирует). Возвращает положение первой ассемблерной команды этой функции внутри EXE- или DLL-файла.

Можно по этому смещению потом пропатчить, например, написать что-то типа return 0.
Code (perl): скопировать код в буфер обмена
# Notes:
# *RVA: offset from image LOADED into memory.
# *Raw: offset in EXE file on disk.
#
# When EXE is loaded into memory, its sections (.data, .edata etc.) may be placed
# at different memory addresses. So we need to scan each section to find RVA in it
# and convert to Raw offset using mapping address.
sub getRawOffsetOfExportedFunc {
        my ($fileName, $funcName) = @_;

        # Read all the file into memory (improve speed).
        open (www.perldoc.com/perl5.6/pod/func/open.html)(local (www.perldoc.com/perl5.6/pod/func/local.html) *F, $fileName); binmode (www.perldoc.com/perl5.6/pod/func/binmode.html)(F); local (www.perldoc.com/perl5.6/pod/func/local.html) $/;
        local (www.perldoc.com/perl5.6/pod/func/local.html) $DEBUG = 0;
        local (www.perldoc.com/perl5.6/pod/func/local.html) $FILEDATA = <F>;
        local (www.perldoc.com/perl5.6/pod/func/local.html) @SECTIONS = ();

        # IMAGE_DOS_HEADER = 0
        my $e_lfanew = readunpack("IMAGE_DOS_HEADER.e_lfanew", "L", 60);
       
        # IMAGE_NT_HEADERS = $e_lfanew
        my $SizeOfOptionalHeader = readunpack("IMAGE_NT_HEADERS.SizeOfOptionalHeader", "S", $e_lfanew+4+16);
        my $NumberOfSections     = readunpack("IMAGE_NT_HEADERS.NumberOfSections",     "S", $e_lfanew+4+2);
       
        # Read all EXE sections.
        my $section = $e_lfanew + 24 + $SizeOfOptionalHeader;
        for (my $i=0; $i<$NumberOfSections; $i++, $section+=40) {
                # IMAGE_SECTION_HEADER = $section
                my $VirtualSize      = readunpack("IMAGE_SECTION_HEADER.VirtualSize", "L", $section+8);
                my $VirtualAddress   = readunpack("IMAGE_SECTION_HEADER.VirtualAddress", "L", $section+12);
                my $SizeOfRawData    = readunpack("IMAGE_SECTION_HEADER.SizeOfRawData", "L", $section+16);
                my $PointerToRawData = readunpack("IMAGE_SECTION_HEADER.PointerToRawData", "L", $section+20);
                my $size = $VirtualSize || $SizeOfRawData;
                push (www.perldoc.com/perl5.6/pod/func/push.html) @SECTIONS, [$size, $VirtualAddress, $PointerToRawData];
        }
       
        # IMAGE_OPTIONAL_HEADER.DataDirectory
        my $dataDirectoryRaw        = $e_lfanew+0x78;
        my $ExportTableRVA          = readunpack("IMAGE_NT_HEADERS.ExportTableRVA",       "L", $dataDirectoryRaw);
       
        # IMAGE_EXPORT_DIRECTORY = $ExportTableRVA
        # Convert RVA to raw offset in EXE image (search each section).
        my $exportTableRaw = rvaToRaw($ExportTableRVA) or die (www.perldoc.com/perl5.6/pod/func/die.html) "Could not find raw EXE offset for $ExportTableRVA\n";

        # IMAGE_EXPORT_DIRECTORY = $exportTableRaw
        my $NumberOfFunctions     = readunpack("IMAGE_EXPORT_DIRECTORY.NumberOfFunctions",        "L"$exportTableRaw+20);
        my $NumberOfNames         = readunpack("IMAGE_EXPORT_DIRECTORY.NumberOfNames",            "L"$exportTableRaw+20+4);
        my $AddressOfFunctions    = readunpack("IMAGE_EXPORT_DIRECTORY.AddressOfFunctions",       "L"$exportTableRaw+20+8);
        my $AddressOfNames        = readunpack("IMAGE_EXPORT_DIRECTORY.AddressOfNames",           "L"$exportTableRaw+20+12);
        my $AddressOfNameOrdinals = readunpack("IMAGE_EXPORT_DIRECTORY.AddressOfNameOrdinals",    "L"$exportTableRaw+20+16);
        my @namePointers          = readunpack("IMAGE_EXPORT_DIRECTORY.AddressOfNames->*",        "L*", rvaToRaw($AddressOfNames), $NumberOfNames*4);
        my @funcPointers          = readunpack("IMAGE_EXPORT_DIRECTORY.AddressOfFunctions->*",    "L*", rvaToRaw($AddressOfFunctions), $NumberOfFunctions*4);
        my @ordinals              = readunpack("IMAGE_EXPORT_DIRECTORY.AddressOfNameOrdinals->*", "S*", rvaToRaw($AddressOfNameOrdinals), $NumberOfNames*2);

        # Enumerate all names.
        for (my $i=0; $i<@namePointers; $i++) {
                my $nameRva = $namePointers[$i];
                my $nameRaw = rvaToRaw($nameRva);
                my $name = readunpack("IMAGE_EXPORT_DIRECTORY.AddressOfNames->$nameRva", "Z*", $nameRaw);
                if ($name eq $funcName) {
                        my $ordinal = $ordinals[$i];
                        my $funcRva = $funcPointers[$i];
                        my $funcRaw = rvaToRaw($funcRva);
                        debug("FOUND $name: $ordinal, $funcRva -> $funcRaw");
                        return (www.perldoc.com/perl5.6/pod/func/return.html) $funcRaw;
                }
        }

        # Convert RVA (memory-based) offset to Raw (file-based) offset.
        sub rvaToRaw {
                my ($rva) = @_;
                for (my $i=0; $i<@SECTIONS; $i++) {
                        my $section = $SECTIONS[$i];
                        my $size             = $section->[0];
                        my $VirtualAddress   = $section->[1];
                        my $PointerToRawData = $section->[2];
                        my $offset = $rva - $VirtualAddress;
                        if ($offset >= 0 && $offset < $size) {
                                my $raw = $PointerToRawData + $offset;
                                debug("Found raw offset for $rva: $raw");
                                # If section is non-first in the list, make it first to improve speed.
                                if ($i) {
                                        splice (www.perldoc.com/perl5.6/pod/func/splice.html) @SECTIONS, $i, 1;
                                        unshift (www.perldoc.com/perl5.6/pod/func/unshift.html) @SECTIONS, $section;
                                }
                                return (www.perldoc.com/perl5.6/pod/func/return.html) $raw;
                        }
                }
                debug("Cannot find raw offset for $rva");
                return (www.perldoc.com/perl5.6/pod/func/return.html) undef (www.perldoc.com/perl5.6/pod/func/undef.html);
        }

        # Read part of file starting from $pos. See unpack() syntax.
        sub readunpack {
                my ($title, $fmt, $pos, $size) = @_;
                $size ||= 16;
                my $data = substr (www.perldoc.com/perl5.6/pod/func/substr.html)($FILEDATA, $pos, $size);
                my @result = unpack (www.perldoc.com/perl5.6/pod/func/unpack.html)($fmt, $data);
                debug(sprintf (www.perldoc.com/perl5.6/pod/func/sprintf.html) "%-50s %s", "$title [$pos]:", @result==1? @result : "$result[0], ... ".@result." times");
                return (www.perldoc.com/perl5.6/pod/func/return.html) wantarray (www.perldoc.com/perl5.6/pod/func/wantarray.html)? @result : $result[0];
        }
       
        # Output debug information.
        sub debug {
                print (www.perldoc.com/perl5.6/pod/func/print.html) join (www.perldoc.com/perl5.6/pod/func/join.html)("", @_) . "\n" if $DEBUG;
        }
}
Back to top
View user's profile Send private message Send e-mail
Ant
Сотрудник «Лаборатории»



Joined: 17 Jun 2003
Posts: 6836
Карма: 131
   поощрить/наказать


PostPosted: Wed Nov 23, 2005 6:06 pm (спустя 25 минут; написано за 12 секунд)
   Post subject:
Reply with quote


М

А почему в «Прочем»?
Back to top
View user's profile Send private message Send e-mail
Дмитрий Котеров
Администратор



Joined: 10 Mar 2003
Posts: 13665
Карма: 411
   поощрить/наказать


PostPosted: Wed Nov 23, 2005 6:10 pm (спустя 4 минуты)
   Post subject:
Reply with quote


М

Перенесено из форума: Прочее.
Перенесено в форум: Склад готовых решений :: Perl.
Back to top
View user's profile Send private message Send e-mail
Display posts from previous:   
Post new topic   Reply to topic All times are GMT + 3 Hours
Page 1 of 1    Email to a Friend.
You cannot post new topics in this forum. You cannot reply to topics in this forum. You cannot edit your posts in this forum. You cannot delete your posts in this forum. You cannot vote in polls in this forum. You cannot attach files in this forum. You can download files in this forum.
XML