| Разработка и ромхакинг > Ромхакинг и программирование |
| [NES] Ассемблер перевести в понятный код |
| << < (2/3) > >> |
| Ti_:
--- Цитата: teremochek от 07 Март 2013, 09:40:25 ---как перевести как перевести и понять --- Конец цитаты --- Подскажи как мне перевести испанского на немецкий и понять (знаю русский, английский) ... :ohmy: |
| KABAL:
sergi, полностью с тобой согласен... Машинный код - по мне так проще всего... |
| yur:
Впринципе суть вопроса ясна, а по поводу икса в скобках это может быть и присваивание переменной "х" функции,ну а что бы реализовать твою идею эт надо ассемблер 6502 знать и какую нибудь среду ооп |
| teremochek:
--- Цитата: Ti_ от 07 Март 2013, 10:30:30 ---Подскажи как мне перевести испанского на немецкий и понять (знаю русский, английский) ... :ohmy: --- Конец цитаты --- Нужно было вначале сказать что это Assembler x816. И на скорее всего что его никто не знает... *** Все равно, спасибо за помощь. Кое что в ассемблере я теперь понимаю ^_^ |
| MetalliC:
teremochek, вообще существуют более-менее нормальные "переводчики" машинного кода в C, но только для x86 (пк-шных) процов и ARM (и кстати стоят хрен знает сколько тысяч долларов) вот пример работы: процедурка на асме http://pastebin.com/ahNDrd65 результат на С http://pastebin.com/8ikUSL83 будет ли тебе понятнее такой код на С ? сомневаюсь ;) но большое НО - это декомпил кода, который изначально был написан на С, если бы на входе был рукописный асм - белиберда бы получилась еще та |
| gepar:
--- Цитата: KABAL ---ergi, полностью с тобой согласен... Машинный код - по мне так проще всего... --- Конец цитаты --- Он проще всего, всё просто и понятно, только надо прочитать 500 строчек предыдущего кода чтобы отследить что же там в том регистре лежит-то и откуда оно взялось, а так да, всё хорошо и просто. Ато видишь ли мода пошла со всеми этими классами и наследованием ... :) --- Цитата: teremochek ---И на скорее всего что его никто не знает... --- Конец цитаты --- А как можно написать что-то на том, что никто не знает ? :wacko: |
| teremochek:
--- Цитата: MetalliC от 08 Март 2013, 13:41:20 ---teremochek, вообще существуют более-менее нормальные "переводчики" машинного кода в C, но только для x86 (пк-шных) процов и ARM (и кстати стоят хрен знает сколько тысяч долларов) --- Конец цитаты --- Приходилось иметь дело с таким. Первое что обломило, это куча переменных с неопознанным типом. Ну а когда дошло до этих - "*(_DWORD *)(a1 + 20) = 7;", я понял что ничего не получится.. --- Цитата: MetalliC от 08 Март 2013, 13:41:20 ---вот пример работы: процедурка на асме http://pastebin.com/ahNDrd65 результат на С http://pastebin.com/8ikUSL83 будет ли тебе понятнее такой код на С ? сомневаюсь ;) --- Конец цитаты --- Такой код я хотя-бы могу разобрать. Если выяснить что делает данная функция и проименовать ее, то даже вероятно не будет нужды переименовывать весь код функции.. Другое дело - эти "(*DWORD)*(a1+21)", с которыми неясно что делать.. Как я понял это ссылка на память стека, или что-то вроде того... Но мне нужен Высокоуровневый код, который легко модифицировать и портировать.. --- Цитата: MetalliC от 08 Март 2013, 13:41:20 ---но большое НО - это декомпил кода, который изначально был написан на С, если бы на входе был рукописный асм - белиберда бы получилась еще та --- Конец цитаты --- На сколько мне известно, еще необходимо что-бы версии Языка, на которым изначально был написан код, совпадала с той, в которой будешь работать. По моему не так просто узнать, на какой конкретно версии писалась та - или иная игра.. Вообще, как я понимаю, толковых декомпиляторов ассемблера в высокоуровневый код - не существует. |
| MetalliC:
--- Цитата: teremochek ---Ну а когда дошло до этих - "*(_DWORD *)(a1 + 20) = 7;", я понял что ничего не получится.. --- Конец цитаты --- я понял, C ты нифига не знаешь, иначе сразу было бы понятно что это --- Цитата: teremochek ---Вообще, как я понимаю, толковых декомпиляторов ассемблера в высокоуровневый код - не существует. --- Конец цитаты --- это и есть толковый декомпилятор, в нем все реверсеры в мире и работают, т.е. антивирусные компании, хакеры/крякеры, спецы по поиску уязвимостей в ПО, и просто желающие скоммуниздить чужой код. другой вопрос что ты ни ассемблеров не знаешь, ни высокоуровневых языков, и для тебя надо переводить в почти человеческий язык, типа "языка Ершова" (если .... то... тогда; повторить), при этом с вычисенными переменными (что и зачем), и соответственно названными, а такого не будет, по крайней мере пока не появятся вычислительные машины с искуственным интелектом (без шуток) ну а специалисты при помощи IDA и HexRays за денек-другой вполне реверсят программки небольшого-среднего объема |
| teremochek:
--- Цитата: teremochek от 07 Март 2013, 09:40:25 ---как перевести x = FireballCounter & #%00000001 --- Конец цитаты --- Здесь нечего переводить.Число справа в бинарном формате. Можно записать так: x = FireballCounter AND %00000001 Не совсем понимаю как это работает. Может оператор AND заменить плюсом "+" ? --- Цитата: teremochek от 07 Март 2013, 09:40:25 ---как перевести и понять y = Player_Y_HighPos - 1 == zero --- Конец цитаты --- Здесь тоже нечего переводить. В принципе понять можно так. IF y = (Player_Y_HighPos - 1) AND (Player_Y_HighPos - 1) = zero --- Цитата: teremochek от 07 Март 2013, 09:40:25 ---как перевести y, FireballThrowingTimer = PlayerAnimTimerSet --- Конец цитаты --- Предположу, что так. y = PlayerAnimTimerSet FireballThrowingTimer = y --- Цитата: teremochek от 07 Март 2013, 09:40:25 ---как перевести if lda AreaType == zero --- Конец цитаты --- Здесь возможно так: a = AreaType if a == zero Добавлено позже: --- Цитата: MetalliC от 20 Март 2013, 15:03:11 ---я понял, C ты нифига не знаешь, иначе сразу было бы понятно что это --- Конец цитаты --- Может объяснишь вкратце, если знаешь.. o_0 --- Цитата: MetalliC от 20 Март 2013, 15:03:11 ---это и есть толковый декомпилятор, в нем все реверсеры в мире и работают, т.е. антивирусные компании, хакеры/крякеры, спецы по поиску уязвимостей в ПО, и просто желающие скоммуниздить чужой код. другой вопрос что ты ни ассемблеров не знаешь, ни высокоуровневых языков, и для тебя надо переводить в почти человеческий язык, типа "языка Ершова" (если .... то... тогда; повторить), при этом с вычисенными переменными (что и зачем), и соответственно названными, а такого не будет, по крайней мере пока не появятся вычислительные машины с искуственным интелектом (без шуток) ну а специалисты при помощи IDA и HexRays за денек-другой вполне реверсят программки небольшого-среднего объема --- Конец цитаты --- Я нечего против "IDA и HexRays" не имею. И кстати я его не называл, ты сам сказал ^_^ Тот-же дизассемблер NES, SEGA в нем делается. Знаю там даже специальные плагины для этого есть. Другое дело что это больше Анализатор кода чем декомпилятор. |
| Mr2:
--- Цитата: teremochek от 20 Март 2013, 13:24:40 ---Но мне нужен Высокоуровневый код, который легко модифицировать и портировать.. --- Конец цитаты --- Хватит смешить народ. <_< --- Цитата: teremochek от 20 Март 2013, 13:24:40 ---Вообще, как я понимаю, толковых декомпиляторов ассемблера в высокоуровневый код - не существует. --- Конец цитаты --- Для кого-то и высокоуровневый язык не толковый... :cool: |
| JAM:
Даю реально дельный совет. Вбей в Google фразу типа "6502 opcode list" или "NES ASM opcodes". Наверняка ты найдёшь или голый список команд, или гид с описанием комманд, что тоже хорошо. Скорее всего, на английском. Команд всего 256, но есть много похожих команд, которые можно сгуппировать, например: LDA, LDA,X, LDA,Y или PHA, PHX, PHY и т.п. Всего групп около 30, это не так много. Не обязательно учить команды, достаточно их понимать. Без понимания команд даже код, который ты привёл, даже с комментариями -- как перевод с японского на китайский. Научись понимать команды, и ты будешь знать китайский =) Но даже зная команды, придётся попотеть, чтобы понять, какой смысл в определённой команде. Например, ты будешь понимать, что одна команда считывает значение из памяти по определённому адресу в аккумулятор. Другая команда сравнивает значение с определённым байтом в коде. Третья команда выполняет прыжок при определённом условии, четвёртая команда модифицирует значение в аккумуляторе, а пятая команда сохраняет значение аккумулятора обратно в память по тому же адресу. Вот только, не зная, что находится в RAM памяти по адресу $0123, так и не поймёшь, зачем всё это. Благо, Марио игра изученная, и для неё наверняка есть ROMMap и RAMMap. Для неизученных игр придётся самому отслежить с помощью Debugger'а, что же такое по адресу $0123 и когда оно меняется. Не нужно бояться ASM, как огня. Уж поверь мне. Лет 8 назад я скачал одну дизассемблированную процедуру, долго в неё втыкал, но так ничего и не понял. Прям, как ты сейчас. 4 года назад я стал изучать ассемблер в одиночку, по списку команд. 3 года назад я всё-таки осилил ту процедуру. Даже зная все команды, я месяц втыкал в 27kb текста, пока до меня не начало доходить, что к чему, путём проб и ошибок. С тех пор научился патчи делать для некоторых игр, понимать код в целом, и даже видеть его в HEX-редакторе. Сейчас я как Сайфер из Матрицы, только блондинок и брюнеток не различаю. =) Смотрю на ROM в Hex-редакторе, и вижу где код, где таблицы, где спрайтовая графика, а где всё остальное... Но это только для одной системы. Ассемблер для Сеги для меня до сих пор -- тёмный лес, хотя там есть некоторые успехи. Для одного хака, например, чтобы изменить 20 байт в разных частях ROM'а, мне лично потребовалось 15 часов, а ты хочешь, чтобы всё и сразу одним нажатием кнопки =) И хотя та игра сильно изученная и даже дизассемблирвоанная, в хаке какие-то данные изменены, где-то удлиннены или укорочены массивы и т.п. В итоге, часть данных перенесена, какие-то данные сдвинуты на X байт, какие-то на Y байт, а все остальные -- на Й байт. |
| teremochek:
Спасибо. Хороший совет. |
| teremochek:
Давайте оставим x816, т.к. он сложнее, и посмотрим простой дизассемблер. Вот еще один пример. На этот раз - "Galaxian". --- Код: ---ProcessPlayerBullet: LDA spr_buf(32,ycoo) BEQ skp021 CMP #200 BEQ skp022 tail05: LDA spr_buf(32,ycoo) SEC SBC #4 STA spr_buf(32,ycoo) BCS ret06 skp021: LDA #200 STA spr_buf(32,ycoo) skp022: LDA PlayerDiedThisVsync BEQ PinBulletToPlayer LDA #CHR_Blank STA spr_buf(32,tile) ret06: RTS --- Конец кода --- Подпрограмма - "ProcessPlayerBullet:". В конце стоит "RTS". Т.е. возврат. Похоже на Функцию, как во многих языках. Можно записать так: --- Код: ---Function ProcessPlayerBullet() --- Конец кода --- За место "RTS" - --- Код: ---End Function --- Конец кода --- LDA spr_buf(32,ycoo) Загрузить память в аккамулятор. Это не самый лучший пример, потому что "spr_buf(32,ycoo)" это массив. Очевидно это координата Y "спрайта" - пули игрока. записываем просто: --- Код: ---a = spr_buf(32,ycoo) --- Конец кода --- следующая --- Код: ---BEQ skp021 --- Конец кода --- Я понимаю так. Что-то в роде IF ... GOTO ... Поскольку Compare команды не видно. Наверноо сравниваем с нулем "0" --- Код: ---If a == 0 Then Goto skp021 --- Конец кода --- дальше --- Код: ---CMP #200 BEQ skp022 --- Конец кода --- Сравниваем a и 200 --- Код: ---If a==200 Then Goto skp022 --- Конец кода --- Далее Лабель tail05: Записываются везде по разному. У меня так. #tail05 LDA spr_buf(32,ycoo) --- Код: ---a = spr_buf(32,ycoo) --- Конец кода --- SEC --- Код: ---I=1 --- Конец кода --- SBC #4 'Вычитание с займом ? a = a - 4 ? STA spr_buf(32,ycoo) 'Сохраняем А в память. --- Код: ---spr_buf(32,ycoo) = a --- Конец кода --- BCS ret06 'Условный переход, если перенос. Не понимаю. Пока хватит... |
| vladikcomper:
--- Код: --- SEC SBC #4 STA spr_buf(32,ycoo) BCS ret06 --- Конец кода --- SEC - Задать Carry флаг. SBC отнимает из аккумулятора (А) значение 4 и инвертированное значение Carry-флага. Т.е., если Carry=1, ничего не отнимается, если Carry=0, дополнительно отнимается 1. В процессоре 6502 не предусмотрено отнимание без учета Carry-флага, поэтому флаг Carry специально задается инструкцией SEC, чтобы гарантировать, что SBC отнимает именно 4. SBC очищает флаг Carry, если при выполнении вычитая случилось заимствование (borrow), т.е. результат пересек границу 00-FF. Например, если отнять из 01 число 04, получится FD, тогда флаг Carry будет очищен. Таким образом... BCS - Branch if carry set - переходит, если заимствования не произошло (Carry=1). На языках высокого уровня эту логику можно заменить следующей: "переход, если значение осталось положительным". |
| JAM:
--- Цитата: teremochek от 28 Март 2013, 20:22:50 ---Я понимаю так. Что-то в роде IF ... GOTO ... Поскольку Compare команды не видно. Наверноо сравниваем с нулем "0" --- Конец цитаты --- Да, это короткий вариант сравнения. Если нужно сравнить с нулём, то просто LDA $1234 BEQ Метка Если нужно сравнить с чем-то ещё: LDA $1234 CMP #$56 BEQ Метка |
| teremochek:
vladikcomper, JAM, Спасибо за полезную информацию. Итак, в целом получилась такая функция. --- Код: ---Function ProcessPlayerBullet() a = spr_buf(32,ycoo) If a == 0 Then Goto skp021 If a == 200 Then Goto skp022 #tail05 a = spr_buf(32,ycoo) C_FLAG = 1 a = a - 4 spr_buf(32,ycoo) = a #skp021 a = 200 spr_buf(32,ycoo) = a #skp022 a = PlayerDiedThisVsync If a == 0 Then Goto PinBulletToPlayer a = CHR_Blank spr_buf(32,tile) = a #ret06 End Function 'RTS --- Конец кода --- Теперь можно еще упростить, убрав загрузку в регистры и сохранение из регистров. --- Код: ---Function ProcessPlayerBullet() If spr_buf(32,ycoo) == 0 Then Goto skp021 If spr_buf(32,ycoo) == 200 Then Goto skp022 #tail05 spr_buf(32,ycoo) = spr_buf(32,ycoo) - 4 if spr_buf(32,ycoo) > 0 Then Goto #ret06 #skp021 spr_buf(32,ycoo) = 200 #skp022 If PlayerDiedThisVsync == 0 Then Goto PinBulletToPlayer spr_buf(32,tile) = CHR_Blank #ret06 End Function --- Конец кода --- Возможно хорошая идея, избавиться от Меток ? (label). Получилось вот так. --- Код: ---Function ProcessPlayerBullet() If spr_buf(32,ycoo) == 0 or spr_buf(32,ycoo) == 200 spr_buf(32,ycoo) = 200 If PlayerDiedThisVsync == 0 Then Goto PinBulletToPlayer spr_buf(32,tile) = CHR_Blank Return Endif #tail05 spr_buf(32,ycoo) = spr_buf(32,ycoo) - 4 if spr_buf(32,ycoo) > 0 Then Return spr_buf(32,ycoo) = 200 If PlayerDiedThisVsync == 0 Then Goto PinBulletToPlayer spr_buf(32,tile) = CHR_Blank End Function --- Конец кода --- Метка "#tail05" осталась, т.к. ссылка на нее находится вне. Как оказалось, нужно добавить еще одну часть кода, для ясности картины. Вот эту PinBulletToPlayer: LDA player_x_pos CLC ADC #124 STA spr_buf(32,xcoo) LDX #0 JSR FireHoldoff JSR StartPlayerShootSound JMP tail05 Упрощаем: #PinBulletToPlayer spr_buf(32,xcoo) = player_x_pos +124 FireHoldoff() StartPlayerShootSound() GOTO tail05 Теперь смотрим, что получается вместе: --- Код: ---Function ProcessPlayerBullet() If spr_buf(32,ycoo) == 0 or spr_buf(32,ycoo) == 200 spr_buf(32,ycoo) = 200 If PlayerDiedThisVsync == 0 spr_buf(32,xcoo) = player_x_pos +124 ; PinBulletToPlayer FireHoldoff() StartPlayerShootSound() GOTO tail05 endif spr_buf(32,tile) = CHR_Blank Return Endif #tail05 spr_buf(32,ycoo) = spr_buf(32,ycoo) - 4 if spr_buf(32,ycoo) > 0 Then Return spr_buf(32,ycoo) = 200 If PlayerDiedThisVsync == 0 spr_buf(32,xcoo) = player_x_pos +124 ; PinBulletToPlayer FireHoldoff() StartPlayerShootSound() GOTO tail05 endif spr_buf(32,tile) = CHR_Blank End Function --- Конец кода --- Наверняка можно записать еще проще, пока не знаю... Код без меток получился больше по объему, чем Код с метками. И к тому-же Код с метками воспринимается лучше. |
| teremochek:
Вот. Код без меток получился такой. --- Код: ---Function ProcessPlayerBullet() If spr_buf(32,ycoo) == 0 or spr_buf(32,ycoo) == 200 spr_buf(32,ycoo) = 200 If PlayerDiedThisVsync == 0 spr_buf(32,xcoo) = player_x_pos +124 FireHoldoff() StartPlayerShootSound() else spr_buf(32,tile) = CHR_Blank Return endif Endif do While PlayerDiedThisVsync == 0 spr_buf(32,ycoo) = spr_buf(32,ycoo) - 4 if spr_buf(32,ycoo) > 0 Then Return spr_buf(32,ycoo) = 200 If PlayerDiedThisVsync == 0 spr_buf(32,xcoo) = player_x_pos +124 FireHoldoff() StartPlayerShootSound() endif Loop spr_buf(32,tile) = CHR_Blank End Function --- Конец кода --- Вот такой возник вопрос. ... CMP #5 BCC skp019 ... Потом, в конце Функции встречается ... DEC l_cur_bullet BNE NextEnemyBullet BCC работает без CMP т.е. If a<0 Then Goto skp019 ,а BNE ,будет работать с тем CMP, что написан вначале? Еще, кажется я понял, как записать такое выражение.. Но это только в конкретном случае.. LDA spr_buf(33,xcoo),x ------------------------------ a = spr_buf(33 + x, xcoo) Где 33 + x это номер спрайта.. |
| MetalliC:
--- Цитата: teremochek ---а BNE ,будет работать с тем CMP, что написан вначале? --- Конец цитаты --- BNE пляшет от флага Z, который изменяют почти все команды разве что кроме перехода/возврата, а не только CMP DEC l_cur_bullet --- читаем в http://www.6502.org/tutorials/6502opcodes.html про комманду DEC - Affects Flags: S Z, т.е. после декремента в зависимости от результата взводятся/сбрасываются флаги Zero и Sign BNE NextEnemyBullet итого это можно записать как l_cur_bullet = l_cur_bullet -1; if (l_cur_bullet != 0) goto NextEnemyBullet; ты почему-то думаешь что типа только CMP меняет флаги, но как я уже сказал это делают почти все комманды, даже например LDA - после записи числа в аккумулятор будут изменены флаги S и Z, грубо говоря CMP делается как бы автоматом после почти всех операций |
| teremochek:
Если я правильно понял, то CMP перед BCC, BCS стоят не просто так. И по видимому записать такую последовательность: CMP #5 BCC skp019 CMP #17 BCS DoneWithThisBullet можно так: if a - 5 < 0 Then Goto skp019 if a - 17 >= 0 Then Goto DoneWithThisBullet |
| GManiac:
Конечно, не просто так, CMP - это явное сравнение. Сравнение - это простановка флагов. После многих арифметических и не только команд происходит неявное сравнение результата с нулём, и это может использоваться в следующих командах - обычно, бранчах, но иногда и в других командах и даже в последовательности команд. Что может привести к не совсем очевидной логике для неопытного чтеца. А если нужно сравнить произвольный операнд с произвольным числом, тут CMP и помогает. Это самое неявное сравнение, точнее, простановка флагов (причём не всех всегда - некоторые команды проставляют не все флаги), делает асм более гибким, чем ЯВУ, но может усложнить понимание. В сях есть что-то похожее, когда можно и операцию произвести, и сравнение сразу, вроде if (--a > 0) {...}; Две последние строки можно упростить: if a < 5 then ... if a >= 17 then ... Добавлено позже: Насчёт "не всех флагов": для M6502 могу ошибаться, но для M68k есть такое. |
| Навигация |
| Главная страница сообщений |
| Следующая страница |
| Предыдущая страница |