Разработка и ромхакинг > Ромхакинг
[NES] Ассемблер перевести в понятный код
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 есть такое.
Навигация
Перейти к полной версии