Описание функций встроенного языка
Скачать 2.86 Mb.
|
void fclose (long handle); Функция закрывает файлы, открытые с помощью fopen. В момент закрытия файла в него записываются все данные, находящиеся в этот момент во внутренних буферах, а файловый объект (то есть то, на что ссылается дескриптор) уничтожается, предотвращая утечку ресурсов. Файлы автоматически закрываются в момент завершения работы породившего их скрипта (при условии, что обладающая дескриптором процедура не описана как static), а так же при корректном завершении работы IDA. В противном же случае операционная система все равно освободит все ресурсы, принадлежащие процессу, но при этом не будут записаны данные, оставшиеся во внутренних буферах. Функция не возвращает результата успешности операции. Операнд Пояснения handle Дескриптор открытого файла Пример использования: Auto a; A=fopen(“PRN”,”wt”); If (a!=-1) writestr(a,”Hello,Printer!”); fclose(a); 340 Обратите внимание, что в приведенном примере fclose выполняется даже тогда, когда файл не был успешно открыт. Это не ошибка, поскольку fclose(0) не приводит ни к каким побочным последствиям. long filelength (long handle); Функция возвращает логическую длину открытого файла. То есть длину с учетом не записанных внутренних буферов, которая может не совпадать с физическим размером файла на диске в данный момент. Длина символьных устройств (таких, как PRN, например) всегда равна нулю. Например: Message(“0x%X \n”,filelngth(fopen(“PRN”, “wt”)); 0x0 Операнд Пояснения handle Дескриптор открытого файла long fseek (long handle,long offset,long origin); Функция позиционирует указатель в открытом файле. Флаг origin, задающий необходимое позиционирование может принимать следующие значения, перечисленные ниже в таблице: origin Значение 0 Позиционировать относительно начала файла 1 Позиционировать относительно текущей позиции 2 Позиционировать относительно конца файла Правда вплоть до версии 4.0 эта функция реализована с ошибкой, приводящей к тому, что флаг ‘1’ трактуется точно так, как и ‘0’ – то есть относительно начла файла. Это видно на следующем примере: auto a; a=Fopen(“myfile”,”wt”); fseek(a,0x10,0); Message(“0x%X \n”,ftell(a)); fseek(a,0x0,1); Message(“0x%X \n”,ftell(a)); fclose(a); 0x10 0x0 Так же не поддерживается отрицательная адресация относительно начала файла. Относительно конца файла можно свободно позиционироваться в двух направлениях. auto a; a=Fopen(“myfile”,”wt”); fseek(a,0x0,2); 341 Message(“0x%X \n”,ftell(a)); fseek(a,0x5,2); Message(“0x%X \n”,ftell(a)); fseek(a,-0x5,2); Message(“0x%X \n”,ftell(a)); fclose(a); 0x100 0x105 0x100 Напомним, что ранние версии DOS содержали ошибку, приводящую к тому, что наращивании размера файла с помощью функции позиционирования сверх определенного размера (зависящего от многих обстоятельств) нарушалась целостность FAT16. Та же ошибка повторена в первых реализациях FAT32 (Windows 95 OSP0, в народе прозванная «Лебединая редакция») При перемещении указателя за конец файла в него подает, информация, расположенная в выделяемых ему дисковой подсистемой кластерах. При этом файл не должен быть открыт на запись, иначе игнорируя флаг, функция будет вычислять смещение относительно файла и его содержание окажется утерянным! Так же оно окажется утерянным, если указать неверное отрицательное смещение или origin > 2. Операнд Пояснение Handle Обработчик открытого файла Offset Смещение (относительно конца файла - знаковое) Origin Указывает, относительно чего отсчитывается смещение (смотри таблицу выше) Завершение Возвращаемое значение Успешно 0 Return Ошибка !=0 long ftell (long handle); Функция возвращает текущую позицию указателя в открытом файле относительно его начала. Операнд Пояснения handle Дескриптор открытого файла Завершение Возвращаемое значение Успешно Текущая позиция Return Ошибка -1 success loadfile (long handle,long pos,long ea,long size); Функция позволяет загружать бинарный файл (или его часть) в произвольный регион виртуальной памяти IDA. Это позволяет писать свои динамические загрузчики, но и эмулировать работу оверлеев, а так же многое другое. Перед началом операции искомый файл необходимо открыть в бинарном режиме функцией fopen с правами только на чтение. Если открыть на запись, то его содержимое окажется необратимо уничтожено! 342 Затем указать позицию в файле для чтения (аргумент pos). Позиция всегда считается относительно начала файла, не зависимо от текущего положения указателя. Далее указать виртуальный линейный адрес, по которому будет скопирован фрагмент файла. Операция завершится независимо от того, производится загрузка в границах существующего сегмента или вне оных. При необходимости IDA выделяет дополнительную виртуальную память для загрузки. Последний аргумент, передаваемый функции – это число загружаемых из файла байт. Если оно превосходит длину «хвоста» файла (то есть от указанной позиции до конца), то IDA выдаст предупреждение: Can't read input file (file structure error?), only part of file will be loaded... И загрузит столько байт, сколько сможет. seg000:2C93 aWatchAvialable db 'Watch avialable DOS memory...........................' auto a; a=fopen("readme.txt","rb"); loadfile(a,0,0x12C93,0x40); seg000:2C93 aWatchAvialable db 'This patch allows you to permanently access the bonus’ Обратите внимание, что загрузка не вызывает реассемблирования исследуемой программы. При этом только перезаписывается соответствующий регион виртуальной памяти, но не меняются связанные с ней флаги! Это хорошо видно на следующем примере: seg000:02E4 sub_0_2E4 proc near ; CODE XREF: seg000:232Ep seg000:02E4 push ds seg000:02E5 xor ax, ax seg000:02E7 mov ds, ax ; DS == NULL seg000:02E9 assume ds:nothing seg000:02E9 seg000:02E9 MyLabel: seg000:02E9 mov ax, ds:413h seg000:02EC shl ax, 6 seg000:02EF cmp ax, 0A000h seg000:02F2 pop ds seg000:02F3 assume ds:seg000 seg000:02F3 retn seg000:02F3 sub_0_2E4 endp auto a; a=fopen("readme.txt","rb"); loadfile(a,0,0x102E4,0x40); seg000:02E4 sub_0_2E4 proc near ; CODE XREF: seg000:232Ep seg000:02E4 push sp seg000:02E5 push 7369h seg000:02E7 jnb loc_0_309 ; DS == NULL seg000:02E9 assume ds:nothing seg000:02E9 seg000:02E9 MyLabel: seg000:02E9 jo loc_0_34C seg000:02EC arpl [bx+si+20h], bp seg000:02EF popa seg000:02F2 outsw seg000:02F3 assume ds:seg000 343 seg000:02F3 ja near ptr loc_0_367+1 seg000:02F3 sub_0_2E4 endp Обратите внимание, что не только сохранились прежние метки, комментарии и перекрестные ссылки, но и оказался неверно дизассемблированным код! Но это не ошибка IDA, а ее архитектурная особенность. Вместе с обычными перекрестными ссылками сохранились и так называемые ссылки на следующую инструкцию. Поэтому вновь загруженный код был дизассемблирован с учетом прежнего «каркаса» то есть линейный адресов начала инструкций. Что бы исправить ситуацию, необходимо пометить измененный фрагмент, как undefined и потом его заново ассемблировать. В результате получится следующее: seg000:02E4 push sp seg000:02E5 push 7369h seg000:02E8 and [bx+si+61h], dh seg000:02EB jz loc_0_350 seg000:02ED push 6120h seg000:02F0 ins byte ptr es:[di], dx seg000:02F1 ins byte ptr es:[di], dx seg000:02F2 outsw Чаще всего эту функцию используют для частичного дизассемблирования файла. Например, если внутри много мегабайтовой DLL необходимо исследовать лишь небольшой фрагмент, то нет нужды несколько часов ждать пока IDA дизассемблирует ее целиком – достаточно лишь загрузить требуемый фрагмент. Кроме того, многие приложения во время работы подгружают различные свои компоненты с диска. Если их так же необходимо исследовать, то для этого можно воспользоваться loadfile. Иногда даже не требуется создавать для этого дополнительный сегмент, загрузив данные за его границы. seg000:32A0 db 0E2h, 20h, 0A4h, 0A0h, 2 dup(0ADh), 0EBh, 0A9h, 20h seg000:32A0 db 0ACh, 0A5h, 0E5h, 0A0h, 0ADh, 0A8h, 0A7h, 0ACh, 21h seg000:32A0 db 0 seg000:32A0 seg000 ends seg000:32A0 seg000:32A0 seg000:32A0 end start auto a; a=fopen("readme.txt","rb"); loadfile(a,0,0x102E4,0x10); seg000:32A0 db 0E2h, 20h, 0A4h, 0A0h, 2 dup(0ADh), 0EBh, 0A9h, 20h seg000:32A0 db 0ACh, 0A5h, 0E5h, 0A0h, 0ADh, 0A8h, 0A7h, 0ACh, 21h seg000:32A0 db 0 seg000:32A0 seg000 ends seg000:32A0 end start 0:000132EA db 54h ; T 0:000132EB db 68h ; h 0:000132EC db 69h ; i 0:000132ED db 73h ; s 0:000132EE db 20h ; 0:000132EF db 70h ; p 0:000132F0 db 61h ; a 0:000132F1 db 74h ; t 0:000132F2 db 63h ; c 0:000132F3 db 68h ; h Доступ к загруженным данным может быть осуществлен, например, вызовами Byte. Для интерактивной же работы (например, что бы преобразовать загруженные данные в строку) все же придется создать сегмент (как это сделать рассказано в описании функции SegCreate) 344 MySeg:000A ; Segment type: Regular MySeg:000A MySeg segment byte public '' use16 MySeg:000A assume cs:MySeg MySeg:000A ;org 0Ah MySeg:000A assume es:nothing, ss:nothing, ds:nothing, fs:nothing, gs:nothing MySeg:000A aThisPatchAllow db ' This patch allows you to permanently access the bonus track ' MySeg:000A MySeg ends MySeg:000A Строго говоря, приведенный пример дизассемблирован не правильно. Если программа подгружала ресурсы из текстового файла динамически во время работы, то перемещение их в сегмент может даже нарушить ее работоспособность после ассемблирования и уж точно не изменит алгоритм, так что бы файловый обмен заменился обращением к памяти. Но на этапе исследования дизассемблируемого кода это невероятно удобно. Можно даже вычислить какие инструкции, какой код загружают, и создать перекрестные ссылки для обеспечения быстрого перехода между различными фрагментами дизассемблируемого текста. Операнд Пояснения handle Обработчик открытого только на чтение файла pos Позиция в файле, относительно его начла ea Линейный адрес начала региона виртуальной памяти Size Число байт для чтения Завершение Пояснения 0 Функция завершилась неуспешно Return 1 Функция завершилась успешно success savefile (long handle,long pos,long ea,long size); Функция, обратная loadfile (смотри описание выше). Она позволяет сохранить фрагмент виртуальной памяти на диске в виде файла. Например: seg000:03D3 sub_0_3D3 proc near ; CODE XREF: seg000:03C7p seg000:03D3 push ax seg000:03D4 push bx seg000:03D5 mov al, byte ptr es:loc_0_F+1 seg000:03D9 mov bx, 3EAh seg000:03DC seg000:03DC loc_0_3DC: ; CODE XREF: seg000:03E4j seg000:03DC cmp [bx], al seg000:03DE jz loc_0_3E7 seg000:03E0 inc bx seg000:03E1 cmp byte ptr [bx], 0 seg000:03E4 jnz loc_0_3DC seg000:03E6 inc bx seg000:03E7 seg000:03E7 loc_0_3E7: ; CODE XREF: seg000:03DEj seg000:03E7 pop bx seg000:03E8 pop ax seg000:03E9 retn seg000:03E9 sub_0_3D3 endp seg000:03E9 seg000:03EA aDeifxcblst db 'DEIFXCBLST',0 auto a; a=fopen(“fileme”,"wb"); 345 savefile(a,0,0x103D9,0x200); ╔═ [ ] ═══════════════════════════ F:\IDAF\fileme ═════════════════════ 23:28:03 ╗ ║ 00000000: 50 53 26 A0 10 00 BB EA 03 38 07 74 07 43 80 3F ¦ PS&а .+ъ 8 t CА? ║ ║ 00000010: 00 75 F6 43 5B 58 C3 44 45 49 46 58 43 42 4C 53 ¦ .uЎC[X+DEIFXCBLS ║ Возможность сохранения отдельных фрагментов файла очень полезна и может стать основой для множества утилит (например, такой, что извлекает все текстовые строки, встретившиеся в программе в отдельный файл) Кроме того, она пригодится, если необходимо сохранить модифицированный вызовами PatchByte файл на диск. Дело в том, что IDA не поддерживает экспорт ни во что другое, кроме com и MS-DOS EXE. И то, и другое, очевидно, давным-давно устарело. И поддержку формата популярных сегодня PE файлов придется реализовывать самостоятельно. Перед началом операции необходимо открыть целевой файл на запись с помощью функции fopen и передать savefile его дескриптор. Позиция в файле для записи может быть выбрана любая, как внутри, так и вне него. Однако, в последнем случае возможно разрушение FAT, поэтому необходимо соблюдать дополнительные меры предосторожности. Размер записываемого фрагмента может превосходить длину дизассемблируемого файла, в этом случае «хвост» будет заполнен символами 0xFF, (именно такое значение возвращает функция Byte при попытке чтения несуществующих адресов), но функция, не смотря на это завершится без ошибки. Операнд Пояснения handle Обработчик открытого на запись файла pos Позиция в файле, относительно его начла ea Линейный адрес начала региона виртуальной памяти Size Число байт для записи Завершение Пояснения 0 Функция завершилась неуспешно Return 1 Функция завершилась успешно long fgetc (long handle); Функция читает один байт из файла. При этом файл должен быть предварительно открыт вызовом fopen с правами, разрешающими чтение. Относится к функциям стандартной библиотеки Си. При неуспешном возращении возвращает ошибку BADADDR – иначе очередной считанный символ. Если не достигнут конец файла, то указатель увеличивается на единицу. Пример использования: auto a,ch; a=fopen(“readme.txt”,”rt”); while((ch=fgetc(a))!=-1) Message(ch); fclose(a); This patch allows you to permanently access the bonus track and bonus car without winning the tournaments. Операнд Пояснения handle Дескриптор открытого с правами на чтения файла 346 Завершение Пояснения Норма Считанный символ Return Ошибка BADADDR long fputc (long byte,long handle); Функция записывает один байт в файл. Файл должен быть предварительно открыт с правами на запись функцией fopen. При неуспешной записи возвратит ошибку BADADDR, иначе ноль. Операнд Пояснения byte Записываемый символ handle Дескриптор открытого с правами на запись файла Завершение Пояснения Норма 0 Return Ошибка BADADDR long fprintf (long handle,char format,...); Ближайший аналог известной функции sprintf, однако, вместо буфера результат копируется в файл. Очевидно, что файл должен быть предварительно открыт с правами на запись вызовом fopen. Например: auto a,s0; s0=0x123; a=fopen(“CON”,”wt”); fprintf(a, "%x \n",s0); 123 Управляющие символы стандартные, и частично совместимые с 'printf' и полностью совместимы со спецификаторами функции Message встроенного языка IDA. Сф пояснение %d десятичное длинное знаковое целое Пример: Message(“%d”,0xF); 15 %x шестнадцатеричное длинное целое строчечными символами Пример: Message(“%x”,10); a %X шестнадцатеричное длинное целое заглавными символами Пример: Message(“%X”,10); A %o восьмеричное длинное знаковое целое Пример: Message(“%o”,11); 13 %u десятичное длинное беззнаковое целое 347 Пример: Message(“%u”,-1); 4294967295 %f десятичное с плавающей точной Пример: Message(“%f”, 1000000); 1.e6 %c символьное значение Пример: Message(“%c”,33); ! %s строковое значение Пример: Message(“%s”,”Hello, Word! \n”); Hello, Word! %e вывод чисел в экспоненциальной форме Пример: Пример: Message(“%e”, 1000000); 1.e6 вывод чисел в экспоненциальной форме ЗАМЕЧАНИЕ: В оригинале спецификатор '%g' заставляет функцию саму решать, в какой форме выводить число - с десятичной точкой или в экспоненциальной форме, из соображений здравомыслия и удобочитаемости. IDA всегда при задании этого спецификатора представляет числа в экспоненциальной форме. %g вывод указателя (не поддерживается) ЗАМЕЧАНИЕ: вместо спецификатора '%p' IDA использует '%a', преобразующее линейный адрес в строковой сегментный, и автоматически подставляет имя сегмента. Так, например, 'Message("%a \n",0x10002 ) ' выдаст 'seg000:2 '. Обратите внимание, что таким способом нельзя узнать адрес переменной. Пример: auto a; a="Hello!\n"; Message("%a \n",a); 0 Возвращается ноль, а не указатель на переменную. %p вывод десятичного целого всегда со знаком, не опуская плюс. %+d в оригинале - вывод шестнадцатеричного целого всегда со знаком, но ida воспринимает эту конструкцию точно так же как и ‘x'. %+x 'n' длина выводимого десятичного числа, при необходимости дополняемая слева пробелами. Например: Message("Число-%3d \n”,1) ; Число- 1 Если выводимое число не укладывается в 'n' позиций, то оно выводится целиком. Например: Message("Число-%3d \n”,10000) ; Число-10000 %nd 'n' длина выводимого шестнадцатеричного числа, при необходимости дополняемая слева пробелами. Например: 348 Message("Число-%3x \n”,1); Число- 1 Если выводимое число не укладывается в 'n' позиций, то оно выводится целиком. Например: Message("Число-%3x \n”,0x1234); Число-1234 %nd ‘n’ длина выводимого десятичного числа, при необходимости дополняемая слева незначащими нулями. Пример: Message("Число-%03d",1); Число-001 Если выводимое число не укладывается в ‘n’ позиций, то оно выводится целиком. Пример Message("Число-%03d",1000) Число-1000 %0nx ‘n’ длина выводимого шестнадцатеричного числа, при необходимости дополняемая слева незначащими нулями. Пример: Message("Число-%03x",0x1); Число-001 Если выводимое число не укладывается в ‘n’ позиций, то оно выводится целиком. Пример: Message("Число-%03x",0x1234); Число-1234 %#x Вывод префикса ‘0x’ перед шестрадцатиричными числами Пример: Message(“%#x”,123); 0x123 %#o Вывод префикса ‘0’ перед восьмеричными числами Пример: Message(“%#o”,1); 01 %n Количество выведенных символов (не поддерживается) long readshort (long handle,long mostfirst); Функция считывает два байта из файла. До начала операции файл должен быть открыт функцией fopen с правами на чтение. Примечательной особенностью данной функции является возможность трансляции знакового бита во время чтения. Если флаг mostfirst равен нулю, то функция будет полагать, что знаковый бит, расположен «слева», то есть, идет самым старшим в слове. Наоборот, если флаг mostfirst равен единице, то функция будет ожидать, что знаковый бит, расположен «справа» то есть идет самым младшим в слове. В случае если во время выполнения функции возникнут ошибки, то будет возращена константа BADADDR – иначе 16-битное прочитанное значение. |