Хочу сделать динамическое добавление строчек в секцию дата или в код , это 2 таблицы , одна с крк и вторая с адресами апи функций. Смысл в том что в проге используется слишком много апи и менять их нужно быстро , тоесть это придется перестраивать таблицы вручную. Удалять и добавлять нужное. Как можно макросом заменить эти действия когда код сам по себе вызывается колом в данные в дате. Я думал так например .code Callx MessageboxAx А макрос будет такой Call macro тут действия для инициализации двух структур типа в зависимости от данных в параметре MessageboxAx dd 0 и MessageboxAxCRC dd 0 хотелось бы разделить по библиотекам еще , например MessageboxAx пойдет в структуру ЮСЕР32 а MessageboxAxCRC dd 0 пойдет в структуру Юсер32КРК. Как можно добавить динамическое определение библиотек и добавление в разные структуры данных для вызова ? Что то вроде такого , это быстрый набросок поэтому явно не рабочий но идея чтоб видна была Код (Text): macro MessageVector message1, message2:REST IFNB <user32> user32CrcApi struct MessageVectorCrcApi dd 0 dd 000000000h user32CrcApi ends user32Api Struct MessageVectorApiStruct dd 0 user32Api ends ENDIF endm MessageVector
calidus IMHO два противоречивых требования: 1) добавление строчек в секцию import/export т.е. программа еще не компилирована 2) в проге используется слишком много апи и менять их нужно быстро, т.е. программа уже скомпилирована, запущена, но вот вопрос -- секция импорта уже загружена, можно ли добавлять туда новые dll и функции? По второму вопросу, по-моему логично перед вызовом непрописанной в импорт функции проделать следующее Код (Text): invoke LoadLibrary,LIBR;загрузить библиотеку mov [hLib],eax invoke GetProcAddress,[hLib],NameProc ;вызвать процедуру с двумя параметрами push dword[hLib] push [hWnd] CALL eax invoke FreeLibrary,[hLib];закрыть библиотеку
link -debug YourProg.obj kernel32.lib user32.lib gdi32.lib wsock32.lib ...итд... Оно само определит заюзаные функи и прикрутит вам правильный импорт. А может я ничего не понял? Если вы хотите править импорт по самому себе, то учтите - статическое импортирование производится только при загрузке, переписать самого себя не просто, и exe-шник для таких целей вам придется линковать вручную сразу, или править под себя / писать свой линкер. Ну а у правильно слинкованого (таблицы импорта должны идти последними) можно править их на лету. Только зачем это вам?
_basmp_ Может быть я чего-то не понял, но можно таблицы импорта писать вручную в бинарный файл и обходится без линкера, как это сделано в NASM и FASM Код (Text): ; nasm windows gui # ; nasmw hello.asm -o hello.exe %define exebase 0x400000 %define MB_OK 0 %macro invoke 1-* ; macro to call Win32 API functions %rep %0 - 1 ; repeat for each argument %rotate -1 ; rotate right (last becomes %1) push %1 ; push argument %endrep %rotate -1 ; %1 = function name call [%1] ; call API function via IAT %endm [BITS 32] ORG exebase ;for WinXP - 335 bytes dd 'MZ','PE',1014Ch,0,0,0,10F0080h,10Bh,END_SECTION-start,0,0,start-exebase dd start-exebase,0,exebase,4,4,4,0,4,0,END_SECTION-exebase,start-exebase,0,2 dd 100000h,1000h,100000h,1000h,0,4,0,0,import-exebase,end_import-import,0,0 dd 0,0,'.text',0,start-exebase,END_SECTION-start,start-exebase,0,0,0 dd 0E0000020h ;--------------------------------------------------------------------- start: invoke MessageBox,eax,Message,wTitle,eax;MB_OK retn ;---------------------------------------------------------------------- wTitle db 'Iczelion Tutorial #2:MessageBox',0 Message db 'Win32 Assembly with NASM is Great!' ;---------------------------------------------------------------------- import: dd 0,0,0,user32_dll-exebase dd user32_table-exebase,0,0 user32_table: MessageBox dd _MessageBox-exebase dw 0 _MessageBox db 0,0,'MessageBoxA',0 user32_dll db 'user32' end_import: END_SECTION:
=) СПсб но вы меня не поняли , читайте еще раз. Обьяснил доступно .. Зачем мне в компилированном файле менять импорт и количество АПИ ? =) НЕТ это не то ! Речь идет об обыкновенных двух таблицах которые вы пишете для заполнения крк и адресов АПИ. Обычно их пишут в код или в дату сразу потом компилируют прогу и эти дворды заполняются данными. Смысл в том что Таблицы пустых двордов для крк и апи будут формироваться макросами во время компиляции. Что убирает работу ручного создания таблиц для крк и апи. Также по идее хотелось бы чтобы он сам определял с какой либы апи и делал дворд в таблицу юсер32 например. Разве мой макрос выше похож на за мену кода динамически в скомпиленной проге ? .. )))))))) Ну вот !
а зачем крк? чтоб вручную искать в образе дллки? ну вот например сделать импорт как в фасме тольк вместо имен -крк...
GoldFinch ))))))) не надо отвлекаться , эти части уже сделаны и все оптимизировано и впорядке. что и надо было =) затруднения в макросе функциональность которого я описал =)
calidus Абсолютно ничего не понятно. В чем вы затрудняетесь и что хотите сделать. В масм вы просто вызываете нужные функи, весь импорт будет построен и соптимизирован без всяких лишних телодвижений. В фасме макросы для импорта уже есть. В стандартную поставку входят.
Нету импорта , прога без импорта. Забей на импорт и если хочется помочь прочитай еще раз. Известные люди в асм сцене поняли меня , но не знают хорошего решения только предположения. Если не понятно ну значит не судьба )))
Прочитал много раз. Чтобы юзать какието функции (или вообще имена), их надо до этого определить. Для этого составляется список всех известных функций, затем при втором проходе компилятора проверяется была ли эта функция использована (if used FuncName), если да - то производятся какие-то действия: добавление в импорт, или в твоем случае добавление в таблицу крк. Другой вариант - функция вызывается через макрос, который определяет где брать адрес для вызова. Для этого макрос добавляет каждую новую функцию в список, затем в конце файла (или при 2м прохоже компилятора) другой макрос из этого списка делает нужные таблицы. Но в этом случае надо задать длл в которой живет функция. И тот и другой способ реализуется на фасме минут за 5, про масм не скажу, т.к. уже забыл как им пользоваться.
calidus Ну чтож. Дело ваше. Хотите доказать, что в чем-то нет решения - доказывайте. Не буду вам мешать.
если несколько упростить и обобщить то что хочет ТС, то получим некий набор макросов, который при вызове например invoke kernel32.Sleep, 100 во время компиляции сгенерирует код для загрузки kernel32, поиска там Sleep по ее хэшу и дальнейший вызов найденной функции с переданными параметрами
чтобы не быть голословным - 1й вариант Код (Text): ... call MessageBoxA ;сам вызов ... ;списки всех апи kernel32_list equ AddAtomA, AddAtomW, AddConsoleAliasA, ... user32_list equ ... .... ;списки крк (можно заменить на вычисление средствами компилятора AddAtomA_crc = 12345 AddAtomW_crc = 23456 ... ;таблицы переходников kernel_thunk_table: irp name,kernel32_list { if used name / make_import name / end if } user_thunk_table: irp name,user32_list { if used name / make_import name / end if } ;макрос объявления переходника macro make_import name { db 90,90,90 ;align name db E9 ;здесь будет jmp dd name#_crc;здесь брать крк и писать адрес } .... ;код заполнения переходника lea edi, [kernel_thunk_table+ecx*8+4] mov esi,[kernel_base] call crc2addr ;функция поиска апи в длл с базой esi по крк в [edi], результат в [edi]
Можно и больше автоматизации... в фасме вообще можно во время компиляции разбирать таблицы экспорта системных длл и сразу прописывать адреса... ну или искать в какой длл находится функция. Однако чем городить килобайты текста макросов лучше написать отдельный препроцессор на чемнить типа пхп, строчек 20 будет наверное.
GoldFinch препроцессор, пхп..) А на его отладку и доводку до кондиции сколько времени уйдет?) По своему опыту могу сказать что уж лучше убить день и написать 10кб аццких макросов которые потом с минимальными усилиями можно внедрить во все проекты, чем городить препроцессор вместо использования встроенного или ручками все править. Тут проблема то только в том, чтобы разобраться как правильно на макроязыке писать чтоб работало, и работало как надо =) Кстати судя по кодесу в первом посте, у нас масм
Спасибо =) .. Задача правильно ясна , в том то и дело что на ФАСМ это одно , но работа идет с МАСМ. Примеры тоже хорошие , но в каждом из вариантов примеров есть мелкие недочеты. Конечно их можно доработать и отладить все хорошо. Чтобы смена нужных апи и двордов проводилось 1 правкой или строкой. Над ПХП вариантом я тоже думал , да года 3 назад на нем писал да и прав mz_ в данном случае , мне это не очень подходит. Наверное цель всетаки выяснить вариаты реализации и собрать 1 рабочий классный пример. Поэтому можно не рассматривать каждый пример как конечный вариант =)
вот тебе примерный кодес того что я описал выше - заменяет собой стандартный макрос invoke на собственный, который проверяет переданный параметр. Убрал всякие навороты, прокомментировал значимые и не очень места. Материала хватит для статьи =) Код (Text): ;invoke replacer ;kernel32.Sleep - use conversion ;Sleep - leave as usual import OPTION NOKEYWORD: <invoke> ;переопределяем стандартный макрос invoke MACRO LibNFunc:REQ, p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12,p13,p14,p15,p16,p17,p18,p19,p20 LOCAL pos,counter LOCAL LibNFuncLen ;имя функции (или длл.имя функции) LOCAL iDotPos ;положение разделителя - точки - в строке LibNFuncLen SIZESTR <LibNFunc> ;вычисляем длину строки параметра LibNFunc iDotPos INSTR <LibNFunc>, <.> ;получаем позицию точки в LibNFunc %IF iDotPos ;если обнаружена точка - значит разбиваем переданный параметр на имя длл и имя функции sLib SUBSTR <LibNFunc>, 1, @CatStr(%iDotPos)-1 sFunc SUBSTR <LibNFunc>, @CatStr(%iDotPos)+1, @CatStr(%LibNFuncLen)-@CatStr(%iDotPos) ;проверка не определена ли уже такая длл sStr CATSTR <imf_>, sLib ;создаем имя флага по шаблону imf_имядлл % IFNDEF sStr ;условная компиляция, если еще не определ флаг - определяем его % echo sStr dll ;вывод отладочного сообщения %sStr equ 1 ;определяем флаг imf_имядлл ;а также определяем имя длл в текущей позиции кода .code ;это уже идет в код jmp @F ;перепрыгиваем данные с именем длл до следующей инструкции % sz_&sLib& byte 0 ;определяем в коде имя метки по шаблону sz_имядлл чтобы впоследствии передавать ее в процедуру загрузки длл % $CR sLib ; здесь у меня свой макрос, шифрующий строку, но можно открытым текстом, код вроде будет таким % byte 'sLib',0 @@: ELSE ;% echo sStr already def ;вывод отладочного сообщения ENDIF ;проверяем, определен ли уже флаг imf_имядлл_имяфункции, нужно чтобы не допустить дубликатов при вызове одной и той же функции sStr CATSTR <imf_>, sLib, <_>, sFunc % IFNDEF sStr % echo sStr import %sStr equ 1 ; определяем значение хеша в текущей позиции кода .code jmp @F ;переходим на следующую инструкцию % dw_&sLib&_&sFunc& DWORD $HashString(%sFunc) ;определяем переменную вида dw_имядлл_имяфункции типа DWORD, макрос $HashString() нам подставляет значение хэша @@: ELSE ;% echo sStr already def ENDIF ELSE ; здесь мы в случае если разделитель-точка не был найден в переданном имени функции, а значит перед нами вызов локальной функции (или обычной winapi), ; в данном случае мы не используем хеширование, но выводим предупреждение IFNDEF DEBUG %echo @FileCur(@CatStr(%@Line)) : [LibNFunc] invoked as usual import ENDIF ENDIF ;тут скопипастеный у когото кусок по анализу и запихиванию параметров в стек counter=0 FOR arg,<p20,p19,p18,p17,p16,p15,p14,p13,p12,p11,p10,p9,p8,p7,p6,p5,p4,p3,p2,p1> IFNB <arg> counter=counter+4 pos=@InStr(1,arg,<ADDR >) OR @InStr(1,arg,<addr >) OR @InStr(1,arg,<Addr >) IF pos IF (OPATTR(@SubStr(arg,%pos+5))) EQ 98 lea eax,@SubStr(<arg>,%pos+5) push eax ELSE push OFFSET @SubStr(<arg>,%pos+5) ENDIF ELSE push arg ENDIF ENDIF ENDM ; подходим к вызову самой функции %IF iDotPos ; ##### тут у нас необычный вызов ##### % push dw_&sLib&_&sFunc& % push offset sz_&sLib& call find_api ;вызываем функцию поиска функции ;) Определена как find_api proc lpszLibName: DWORD, dwHashValue: DWORD call eax ; в eax мы получаем найденный адрес. Тут еще бы надо контроль на нулевой указатель и обработчик ошибок чтобы легче было искать проблему ELSE ; #### тут у нас обычный вызов ##### call LibNFunc ENDIF ;IFE iDotPos ;wsprintf fix - а это хрень чтобы подчистить стек для хитрых функций IF ((OPATTR(funcname)) AND 11100000000y) EQ 00100000000y IF counter NE 0 add esp,counter ENDIF ENDIF ENDM