Вы видите копию треда, сохраненную 20 декабря 2018 года.
Скачать тред: только с превью, с превью и прикрепленными файлами.
Второй вариант может долго скачиваться. Файлы будут только в живых или недавно утонувших тредах. Подробнее
Если вам полезен архив М.Двача, пожертвуйте на оплату сервера.
Вы пишите на ассемблере или собираетесь начать на нём писать? Программируете микроконтролёры, пишете драйвера для ОС, а то и саму ОС? Вам сюда.
Вы изучаете алгоритмы работы закрытого софта, пишите патчи бинарников? Вам тоже сюда.
Попрошайки с "решите лабу по асме за меня" идут в общий тред, а лучше нахуй.
Книги по RE:
https://beginners.re/ - "Reverse Engineering для начинающих"- бесплатная современная книга на русском языке. К прочтению вкатывающимся и прочим ньюфагам обязательна!
https://mega.nz/#!Bc9VVAYC!Vk6CFlW6VIoskLNgDKXbsL6FacDQeOKe6LX92wNicKY Нарваха практический курс по дебагингу
https://www.goodreads.com/shelf/show/reverse-engineering - список книг
Сайты по RE:
http://wiki.yobi.be/wiki/Reverse-Engineering
https://www.reddit.com/r/ReverseEngineering/comments/hg0fx/a_modest_proposal_absolutely_no_babies_involved/
http://www.program-transformation.org/Transform/ReengineeringWiki
http://blog.livedoor.jp/blackwingcat/
https://yurichev.com/blog/
http://wiki.xentax.com/index.php/DGTEFF
Инструменты для RE:
1) IDA Pro 7.0.torrent (x64 only, для XP нужно патчить + вылеты)
2) IDA Pro 6.8.torrent
3) IDA Pro 5.0 - бесплатная версия для некоммерческого использования
4) Остальное
Все книги и статьи Криса Касперски (R.I.P.)
https://yadi.sk/d/CxzdM1wyea4WP
+ https://rutracker.org/forum/viewtopic.php?t=272818
Книги по ассемблеру:
"Архитектура компьютера" Э. Таненбаум
С.В. Зубков: Assembler. Язык неограниченных возможностей.
Сайты по ассемблеру:
Замена почившему wasm.ru- https://wasm.in/
https://www.unknowncheats.me/wiki/Assembly
http://asmworld.ru/
https://software.intel.com/en-us/articles/intel-sdm
http://www.nasm.us/doc/
https://sourceware.org/binutils/docs/as/index.html#Top
https://msdn.microsoft.com/en-us/library/afzk3475.aspx
Для ковыряющих винду и софт под неё, сайты с описанием структур со смещениями и разными версиями оных:
http://msdn.mirt.net/
http://terminus.rewolf.pl/terminus/
http://geoffchappell.com/
Предыдущие
№3 https://arhivach.cf/thread/301316/
№4 https://arhivach.cf/thread/369752/ или тонущий https://2ch.hk/pr/res/1126092.html (М)
1 Мониторить папку на изменение
2 Таймер на 1-1,5 секунды
3 Проверка файлов
4 Если всё норм то бэкап
Куски кода уже готовы, кроме таймера. И сам смогу разобраться, просто лень какая-то, и пишу для переката.
Вот так не работает(изменение срабатывает):
invoke ReadDirectoryChanges, [_hFile], fni, MAX_PATH, FALSE, $10, tmp, NULL, NULL
invoke CloseHandle, [_hFile]
invoke SetTimer, 0, 0, 1500, 0
@@:
mov eax, [msg]
cmp eax, WM_TIMER
je @F
jmp @B
А как надо? Желательно попроще.
> А как надо? Желательно попроще.
А оконная процедура где? У тебя msg магически заполняется? А таймер зачем, если ты функцию синхронно вызываешь?
Таймер, потому что игра мне не посылает сообщения о изменённых ей файлах. В процедурах плаваю. Это с заготовки из учебника:
;Диалоговая процедура
proc DialogProc hwnddlg, msg, wParam, lParam
cmp [msg], WM_CLOSE
je FreeDialog
cmp [msg], WM_INITDIALOG
Первое что пришло в голову, это проверить msg на наличие WM_TIMER.
>Пойму ли смысл жизни, изучив ассемблер?
Ассемблер - абстракция над системой команд процессора. Плюс некий синтаксис для описания данных.
Короче, говоря об ассемблере, сначала имей в виду систему команд (x86, arm, MIPS, etc) а затем версию транслятор, ибо даже для одних тех же процессоров синтаксис и нотация может отличаться.
> Таймер, потому что игра мне не посылает сообщения о изменённых ей файлах
Еще раз повторяю: ты вызываешь ReadDirectoryChanges синхронно. Она зависает, пока не произойдут запрошенные изменения. А раз так, таймер тебе зачем? Жди изменений в отдельном тредике, например.
> Первое что пришло в голову, это проверить msg на наличие WM_TIMER.
Почитай про оконные сообщения хоть что-нибудь. Чтобы обработать сообщение, тебе нужно отдать контроль либо своему циклу обработки сообщений (GetMessage/DispatchMessage) либо, если у тебя DialogBoxParam - обратно в DialogBoxParam (там тоже крутится такой же цикл обработки), тогда при обработке DispatchMessage система вызовет твою оконную/диалоговую процедуру с этим сообщением в параметре msg. Т.е., чтобы получать сообщения таймера, который ты создал функцией SetTimer, тебе нужно сначала завершить обработку текущего сообщения и выйти из своей DialogProc - никаким иным магическим способом WM_TIMER в msg не попадет.
>>216733
Двачую этого. Если вся программа сводится лишь к подергиванию Windows API, на Си это можно сделать с гораздо меньшим количеством боли. Исключение - всяческие нестандартные инжекты, хуки и патчи, которые как раз на асме реализуются быстрее и красивее.
Блать, нахуя? У меня всё есть говорю же, остался только таймер. Чё сложного вызвать функцию ReadDirectoryChangesW, если есть изменение то передать управление в блок/процедуру бэкапа, если нет то вызвать функцию messagebox с параметрами sysmodal. И наверняка моя прога будет быстрее и меньше чем высокоуровневая. и конечно же это ощущения кайфа, от того что ты можешь сделать всё что угодно с информацией
>И наверняка моя прога будет быстрее и меньше чем высокоуровневая.
Я частенько анализирую "выхлоп" компиляторов - чего он там намудрил в асме. Т.ч. слово "наверняка" я бы опустил.
> Т.ч. слово "наверняка" я бы опустил
Для редкоиспользуемых архитектур - да. На x86/ARM компилятор обгоняет обычного я-у-мамы-ассемблерщика со свистом и слегка посасывает только на SIMD, да и то не у всех. При этом сишный код можно без проблем модифицировать, а в ассемблерном при каких-то изменениях ручные оптимизации начинают отваливаться, иногда приходится переписывать всю функцию целиком. Нахуй так жить?
>>216759
> Знаете как я это сделаю?
Нихуя не понял, но звучит как максимально бессмысленное извращение.
И откуда я знаю. Вот у меня есть в папке save 100 файлов, игра делает сохранение. Где, что, сколько? Наверняка в высокоуровневых языках есть точное условие.
>Нихуя не понял, но звучит как максимально бессмысленное извращение.
Ну я делаю диалоговое окно из шаблона. Чтобы сделать его с картинкой, нужно чтобы эта картинка была. А я, объёбывая систему, копирую байты этой картинки в строку байт. Во время исполнения программы, создаю файл пикчи и делаю диалоговое окно из шаблона, потом файл пикчи уничтожаю.
>Чтобы сделать его с картинкой, нужно чтобы эта картинка была
Кладешь картинку в ресурсы, кладешь в диалог STATIC c SS_BITMAP и именем ресурса с картинкой, не пишешь ни строчки кода (каждый первый редактор ресурсов в такое может). Ну или кладешь байтики прямо в бинарник, потом CreateBitmapIndirect/SendMessage(..., STM_SETIMAGE, ...) если хочется без ресурсов. Или StretchDIBits, если хочется в жопу, и чтобы было максимально больно.
Спасибо, ты как всегда крут. Но мне нужен таймер - простое решение, чтобы прога останавливалась на секунду.
Я сказал именно то что хотел сказать.
>Вот у меня есть в папке save 100 файлов, игра делает сохранение. Где, что, сколько?
Всё будет так же, как и на ассемблере, только гораздо проще. Вот тебе скрин из моей ранней попытки написать что-то полезное. Здесь асинхронно всё делается, один поток ждёт изменений, а другой поток это изменение обрабатывает, чтобы было максимально быстро. Т.к. это была ранняя попытка что-то писать, не учитывалось условие, что количество одновременно отслеживаемых директорий должно быть меньше 64 и прочие недочёты в виде двух структур. Уже и не вспомню, зачем их две, а не всё в одной. Но сейчас пишу ещё хуже.
>>216845
>объёбывая систему
Нет, только себя.
>>216893
>чтобы прога останавливалась на секунду
Sleep(1000);
Не?
>Уже и не вспомню, зачем их две, а не всё в одной
Для WaitForMultipleObjectsEx, как оказалось.
И? Ты только что доказал мне что высокоуровневые языки плохо влияют на чел. мозг(без обид). Лови мысль, игра начинает сохранение, изменяет первый файл, второй файл, или как-то два файла одновременно. Когда нужно начинать делать бэкап? Игра же мне не вышлет сообщения: я сохранилась, можно делать бэкап.
>высокоуровневые языки плохо влияют на чел. мозг
Нет. Это из-за отсутствия соответствующего образования и работы над каким-то проектом в команде, когда полученные знания можно применить на практике. Кто-то может и без этого обойтись. У меня не получилось. Пишу-пишу, написал, работает. Лучше туда больше не соваться.
>Когда нужно начинать делать бэкап?
Точно в тот момент, когда и ты будешь делать бекап в своей программе. Логика не изменится, разной будет реализация. WinAPI используется один и тот же. Для этой задачи, возможно, C++ будет лучшим решением с его std::map и другими контейнерами. Что у тебя там за игра? Несколько файлов на одно сохранение? Получили изменения, записали в контейнер, используя имя файла без расширения как ключ. Когда получили все изменённые файлы сейва, делаем их бекап. Даже многопоточность не нужна, достаточно будет одного главного потока.
>игра начинает сохранение, изменяет первый файл, второй файл, или как-то два файла одновременно
И ничего не пропадёт. Все изменения будут получены из ReadDirectoryChangesW, сколько бы одновременно их не изменялось/создавалось. Ты же сам будешь использовать эту функцию. Считаешь, что на каком-то C++ или даже питоне всё будет исполняться настолько медленно, что программа не получит некоторые сообщения об изменённых файлах?
Бамп.
>Точно в тот момент, когда и ты будешь делать бекап в своей программе. Логика не изменится, разной будет реализация. WinAPI используется один и тот же.
Да ты тут не прав. Это не будет работать чисто логически. Ты не знаешь тот момент времени в которой игра перестанет делать сохранение, и игра тебе это не сообщит.
Тут дальше последствие высокоуровневых языков.
>Тут дальше последствие высокоуровневых языков.
И ты тут такой выезжаешь на белом коне и объясняешь мне, при чём тут высокоуровневый язык и как в asm ты будешь это определять, что это можно сделать только с помощью низкоуровневого языка.
Ну ладно, а если я тебе скажу что эту прогу я делаю для субнаутики с её 41-м багом(и может быть она решит и другие проблемы). Код уже есть, осталось копипасте, и когда выйду из пике то сделаю таймер. Лавров мне не надо, а ты играешь в Субнаутику?
ОПАНЬКИ. Такой исход ты не предвидел. Чё не смеёшься, не смешно, не понял? А я поясню тебе в каких текстурах ты застрял. Субнаутика - лучшая игра 2018-го года, имеет неисправимый баг с пропаданием сюжетных вещей, это происходит когда игра выгружает хуйню заместо сохранения. И где ты? В каких высокоуровневых текстурах застрял?
Я да, накатил, но я наоборот за мир дружба жевачка.
плез
https://www.youtube.com/watch?v=_7BzngvURrk
Она на коленке делается и стоит 300 рублей, весь мир ждёт пока вы тут дурака валяете. Я не буду себя упоминать, могу сказать что вот привет от 2ch.hk/pr
Остался только таймер.
> это ...?
Это IDA Pro и wine для всего остального. Под линукс нет нормальных инструментов для реверсинга: нет отладчика для людей, нет дизассемблера, даже хекс-редактора нормального нет. radare2 пыжится-пыжится, все на него молятся-молятся, но реверсить в нем - это как редактировать текст в виме - такое себе удовольствие.
>IDA Pro
Установил. А там только посмотреть код в структурированном виде можно? Больше ничего нельзя? Редактировать, например.
>нет отладчика для людей, нет дизассемблера
Даже какого-нибудь GUI поверх GDB нет?
>radare2
Спасибо, посмотрю.
есть гуя поверх radare Cutter, но они еще прибивают гвоздями дебаггер и некоторые штуки из радара в гуй
> Редактировать, например.
Тебе пишут файловый офсет инструкции слева внизу окна с дизасмом. Есть Edit->Patch program, в том числе и с ассемблером для некоторых архитектур (можно плагины поставить для других), есть даже сохранение, если дело касается .exe (не помню, работает ли с .elf). Но пользоваться этим не советую, там есть всякие тонкости вроде релоков, поэтому патчи чем-нибудь внешним лучше.
> посмотреть код в структурированном виде можно
Пробел, Tab.
> Даже какого-нибудь GUI поверх GDB нет?
Есть, но там изо всех щелей ползет gdb. Пользователи Linux не могут в UI. Можно было бы пользоваться связкой IDA+gdbserver, но для этого нужно слишком много телодвижений.
Всегда проигрываю с того, что вроде бы сделали гуй, а всякие хинты control flow нарисованы псевдографикой.
Это шарит.
Прохожу туториал от CheatEngine
Вот есть код, который в EAX записывает то, что хранится в памяти по адресу, который записан в Tutorial-i386.exe+201630
Потом берётся это самое, что там получилось и берётся то, что хранится в памяти, которая находится по адресу, который мы записали в EAX перед этим.
И там уже наше значение 46 из туториала.
Пиздец в общем.
Так вот. Почему на первом скрине
Tutorial-i386.exe+201630 = 0178A5C8 - то, что надо. Там и хранится 46
А на втором скрине
Tutorial-i386.exe+201630 = 00B0707D - вообще не то. Как так?
Почему одно и то же сложение адресов даёт разные результаты?
Tutorial-i386.exe = 00905A4D
00905A4D + 201630 = B0707D (посчитал в калькуляторе) - как на втором скрине. Тогда получается в первом кривая математика. А как тогда там считается?
Нихуя не понял. В нижнем поле плюс вообще не плюс а какая-то магия.
Я думал "Tutorial-i386.exe+4" это "взять адрес начала памяти процесса в оперативке" и "отступить 4 байта". А получается 00000003. 3 байта от начала оперативки? При добавлении 4? Как? Что? Чего вообще?
Правда я хексом открыл файл и вообще не могу найти там то, куда указывал Tutorial-i386.exe+201630
Вот если взять с этого >>219296 первую строку 00905A4D, перевернуть в 4D5A9000, то я нахожу это в самом начале файла.
А если взять 0178A5C8 с первого скрина >>219294 и перевернуть в C8A57801, то в файле ничего такого нет.
По адресу 0x201630 (а в CheatEngine используется 0х, я проверил) используются одни 0xFFFFFFFFFFFFFFFFFF
Так это всё таки адрес в файле или не файле?
Я опять ничего не понимаю.
> Я думал "Tutorial-i386.exe+4" это "взять адрес начала памяти процесса в оперативке" и "отступить 4 байта".
И прочитать значение, прочитать забыл. Справа у тебя там значение. Вот эти байтики (little-endian, 4-байтовые целые числа читаются задом наперед): 4d 5a 90 00 03 00 00 ... (MZђ....) - это заголовок, самое начало любого .exe-файла, сигнатурку MZ отовсюду видать. Соответственно,
>>219294
На втором пике ты читаешь мусор, т.к., MZ - это явно не то, что тебе нужно. А на первом пике у тебя 201630 уже не заголовок, а середина образа, правильное смещение какого-то дворда, в котором лежит какая-то переменная.
>>219304
> Правда я хексом открыл файл и вообще не могу найти там то, куда указывал Tutorial-i386.exe+201630
Офсеты в файле практически никогда не совпадают с офсетами в памяти. При загрузке файл не просто копируется в память - разные куски файла кладутся по разным адресам, по некоторым адресам просто кладутся нули, некоторые части файла вообще не попадают в память. Все это описано в таблице секций файла, поэтому чтобы по виртуальном адресу (в памяти) узнать файловый офсет, нужно пройтись по таблице секций, узнать, в какой секции этот адрес, ну и там дальше уже считать. Как-то так.
Проблема в остановки процесса из за исключений , все настройки переебал. Все равно на каждом исключении останавливает процесс. Подскажите как быть.
Как пример даю скрин с рандомного приложения.
А ты хочешь, чтобы исключения в программу летели? При исключении идешь в третью вкладку у тебя на скрине, говоришь "Добавить последнее".
Хочу чтобы пролетало все кроме моих бряков.
Вот я делаю code injection, как я понял он меняет инструкцию на:
JMP newmem
Где newmem это уже наш код, который размещается в свободном участке памяти.
И этот код в "Auto assemble" не настоящий ассемблер, да? Это язык самого CE, из которого он уже составляет код ассемблера и вставляет его в память. Пик 2.
Так?
Получается alloc(newmem,2048) говорит CE - найди мне 2кб свободной памяти где-нибудь. И дальше в "лейбле" newmem мы можем писать код, ассемблер код которого, будет меньше 2кб. Плюс в этот код будет добавлено то, что в лейбле originalcode.
Плюс будет то, что в лейбле exit, где returnhere это адрес в который надо вернуться из нашей новой памяти. В старую память, которая шла после оригинального кода.
3й пик - после выполнения кода авто ассеблера CE.
Ещё я вот смотрю в новый код, который получился, он с адреса 01730000 до 01730FFF, получается 4095. Но одна команда где мусор занимает сразу 2 байта получается, значит всё правильно.
Первые 3 строки наш код, остальные add [eax],al
Это просто мусор, который в памяти выглядит как нули. "00 00" означает "add [eax],al". Так?
add dword ptr [ebx+00000478],02 в памяти выглядит как 83 83 78 04 00 00 02
sub dword ptr [ebx+00000478],01 в памяти выглядит как 83 AB 78 04 00 00 01
jmp Tutorial-i386.exe+25864 в памяти выглядит как E9 51 58 CF FE
В общем я всё правильно понял (как это всё работает) или всё не так?
Я знаю что там надо удалить sub или делать add 3 чтоб пройти туториал, я уже прошел
> не настоящий ассемблер, да?
Вполне себе нормальный ассемблер.
> Плюс в этот код будет добавлено то, что в лейбле originalcode.
Подозреваю, что ему абсолютно похуй, как ты все это назовешь, и что конкретно там будет. Важны только метка "Tutorial..." и метка newmem. Но если тебе, например, пропатчить sub на nop или на add, а не добавить еще код, то можно пропатчить поверх существующего кода, и ничего выделять не нужно.
> "00 00" означает "add [eax],al". Так?
Да. Но туда управление не попадает, поэтому можешь хоть db "Hacked by Vasyan" туда написать.
>Вполне себе нормальный ассемблер.
Ну в смысле строка "alloc" никак не попадает в память программы. Как и все label и всё остальное. То, что я пишу в окно "Auto assembly" не попадает в память игры. Этот код обрабатывает CE и уже заносит в память игры то, что он там вычислил. В моём случае это jmp, nop, nop и по новому адресу остальной код. Но не всё 1 в 1 как было в "Auto assembly". Там не всё ассемблер в этом окне.
> получается 4095.
Забыл на это ответить. Если пользоваться относительно низкоуровневыми API (а CE ими пользуется), то выделять память можно только блоками, чей размер кратен размеру страницы. Страницы в x86 по большей части 4к (4096 байт), есть еще large pages, но они к делу не относятся. Поэтому когда ты попросил 2к, тебя округлили до границы ближайшей страницы и дали 4к сразу. А то, что 4095, это ты обсчитался: да, fff - это 4095, но мы-то считаем не от 1, а от нуля, и с нулем будет 4096. Ошибка на единицу в диапазонах - классический проеб.
>>220324
> Ну в смысле строка "alloc" никак не попадает в память программы.
Называется "директива ассемблера". У всех ассемблеров они разные, в зависимости от области применения.
>даже хекс-редактора нормального нет
Есть HTE, он же HT Editor, он же просто HT. Для битхака подходит не хуже хиева, еще и позволяет выбрать способ ассемблирования инструкции.
https://www.youtube.com/watch?v=MunG3hrijyY
Про все эти контесты в 4к, 64к. Я сам это помню отдаленно из журналов Игромании. Вот сейчас дико захотелось во все это вкатиться, но где черпать инфу? Где вся движуха в коммьюнити?
> не хуже хиева
Посмотри на 010 Editor и сравни. Хиев тоже ни на что сложнее запатчивания jne не способен. Но меня тут недавно ткнули носом в GNU Octeta, так что хекс-редактор таки есть.
Базара нет, чисто для хекса и для разбора структур в хексе 010 лучше. Но у меня специфические запросы - наличие дизассемблера с ассемблером и работа с популярными форматами исполняемых файлов - Macho-O, PE, ELF и так далее. Обычных хекс редакторов различной степени фичастости навалом, хекс редакторов с перечисленным функционалом, окромя Хиева и HT нет. Был еще biew, впоследствии переименованный в beye, но он благополучно загнулся.
http://sparksandflames.com/files/x86InstructionChart.html
пиздец, где капча?
Там только однобайтовые опкоды. И... зачем? Точно такая же табличка есть в Intel SDM.
>пиздец, где капча?
Из гугла выйди, нуб. И включи нормальную капчу в настройках, чтобы не искать апельсиныю
Лол блядь, а что в ассемблере можно использовать специальную инструкцию цопе, которая определяет было ли сохранение?
Ты понимаешь, что все что можно сделать на ассемблере можно сделать и на языке более высокого уровня, ты как будто считаешь ассемблер какой-то универсальной отмычкой.
В реальной разработке ассемблер используют достаточно редко, в основном только там, где без него никак не обойтисьнапример работа с регистрами
Я тебе даже больше скажу, если ты будешь писать то, что хочешь на си, это мало того что работать будет лучше и быстрее, т.к. компилятор лучше тебя знает, как и где какие инструкции нужно использовать, ты ещё и сам код напишешь в разы быстрее.
мимо-пишу-дрова-под-линукс
Спасибо)
Старые журналы Хакер. Chaos Communication Congress, Chaos Construction
Пагни, нихуя не знаю нихуя не умею, помогите.
Блять
В книге Юричева дается адрес сайта с разными коньпеляторами, чтоб смотреть вывод их на асме. Но я там не нашел как генерировать код для 32х битной машины, от выплевывает асм для 64
godbolt.org? -m32 -masm=intel в строку опций компилятора справа вверху, очевидно же.
Мерси!
Зачем мне спорить с высокоуровневым дурачком? Ты даже не можешь понять что мне нужен только таймер, а ты мне хуй помог, вот и всё, вся логика.
Лол, то есть за две ебаных недели до тебя так и не дошло, что таймер в твоей задаче не нужен?
Да ты сначала дай, потом уже будет видно нужен или нет.
Там сейчас 163 файла, я не знаю сколько их может быть, может 500, а может 1000 к концу игры, тем более игра специфичная. Или предлагайте свой алгоритм бэкапа.
Тебе уже писали выше:
CreateThread(..., changes_listener, ...);
...
void changes_listener(LPVOID arg) {
while (ReadDirectoryChangesW(...)) {
перебираем изменения в буфере, делаем, что нужно
}
}
Со всей обработкой ошибок и обработкой изменений это от силы строчек 50 на Си и куча бессмысленной жопной боли на ассемблере.
Когда в этом коде начинается непосредственно сам бэкап? После каждого изменения?
Бэкап чего? Одного файла? А если этот файл сбэкапился нормально, а в следующем ошибка, тогда что?
> После каждого изменения?
Почему бы и нет? Можешь пачку набирать себе в очередь, логика не меняется.
Да почему не меняется то? У меня тогда в бэкапе будет каша, половина нового, половина старого. Зачем мне такой бэкап? И даже с высокоуровневыми очередями не ясно когда эта очередь должна закончиться, тем более я не знаю сколько файлов там вообще может быть.
После первого изменения в папке программа ждёт, потом проверяет файлы на правильность, затем бэкап. Если нет то ошибка. Это сложнее вашего варианта чтоли?
Быстрее по сравнению с чем?
Насколько быстрее сравнению с Си с -o2?
Всякие математические библиотеки, в том числе для длинной арифметике часто на ассемблере пишут, но только те 20%, которые отвечают за 80% производительности. И для этого нужно гуру ассемблера быть, знать, какая инструкция сколько тактов выполняется и т.п.
Кстати, их использование наверняка оптимальнее самописного кода.
>все что можно сделать на ассемблере можно сделать и на языке более высокого уровня,
Нихуя. Такое мог сказать только васян, который не работал плотно с андоками и со всякими системными "мелочами". Попробуй-ка изменить gdtr из-под си без асма
а в асме надо будет только lgdt исполнить
> Попробуй-ка изменить gdtr из-под си без асма
В Visual Studio уже пару десятилетий есть интринсик _lgdt(). Охуеть, правда?
https://xakep.ru/2018/07/09/voksi-denuvo-crack/
https://www.youtube.com/watch?v=Ka_PudOvWpI
Спасибо, поглядим.
> Даже какого-нибудь GUI поверх GDB нет?
Есть GEF:
https://github.com/hugsy/gef
Я его не пробовал, но с виду попытка создать нечто, внешне похожее на Soft-ICE, неплохая.
На асме не вся реализация, а только та часть, которую на си писать либо неудобно, либо на си было бы очевидно медленнее из-за каких-либо неприятных изворотов.
тТак что да:
>но только те 20%, которые отвечают за 80% производительности
опять бухой кун с таймером
>нас заставляли задрачивать синтаксис заместо программирования, и ты тоже задрачивай
Так это была ошибка
>я могу в асм. Так? так. Я не могу в высокоуровневые языки. Так?
Ты какой-то странный. Какие проблемы в ЯВУ после ЯНУ?
Мне это просто не нужно, бритва Оккама, с этим согласны все, но почти никто этого не делает.
>почему я должен изучать выскоуровневый язык чтобы решить задачу связанную с информацией
Потому что для любой мало-мальски содержательно задачи на ассемблере потребуется огромная простыня, чтобы написать её. Которую невозможно читать и отлаживать.
У меня план такой - писать проги блоками, со временем будет много исходников в которых будут любые блоки. Мне нужно будет их только копировать и изменять под условия задачи, у меня будет больше степеней свободы, я выигрываю.
>Тип nil — это тип с единственным значением, nil, основная задача
которого состоит в том, чтобы отличаться от всех остальных значений.
Lua использует nil как нечто, не являющееся значением, чтобы
изобразить отсутствие подходящего значения.
Ещё, я не хочу размещать у себя в голове такие вот конструкции( скорее опасаюсь).
Я останусь при своём мнении, вы при своём, предлагаю закрыть этот вопрос. Я не хотел никого обидеть, просто пояснил за себя, потому что я буду тут оч. долго, для понимания вобщем.
>Вопрос: почему я должен изучать выскоуровневый язык чтобы решить задачу связанную с информацией? Если асм и есть причина того что эти задачи вообще появились. Где логика? Это не говоря уже о том что заучивать синтаксис это не программирование.
Иди Луговского-Ксеноцефала на sql.ru почитай, может это тебе мозги вправит. Ты мне напоминаешь юродивого, пытавшегося оппонировать ему в крестотреде. Тот тоже нихуя не знал, синтаксис путал с семантикой, не понимал, зачем нужны разные языки и парадигмы и, как положено люмпену, питал слабость к выпивке. Только он считал кресты "высшей ступенью в программизме", а ты копротивляешься за асм.
>как положено люмпену, питал слабость к выпивке.
https://www.youtube.com/watch?v=ZwyxoIYBxLg
Чем я вас так сильно зацепил? Почему нельзя оставить всё как есть? Я же всё объяснил. Я не считаю вашу позицию неверной, просто у меня другая позиция.
То что я иногда обзывался? Потому что бухой был, а у меня пьяного шифер капитально сползает(поэтому пытаюсь реже бухать).
Почитаю
Есть android игра (dream league soccer 2018), в которой прогресс сохраняется в пользовательском пространстве в двух (судя по всему 1 проверочный) файлах. В profile.dat , содержатся структуры и данные всего профиля, которые можно осмысленно редактировать hex редактором. profile_cld_u же, мне кажется, является упакованным profile.dat предыдущего матча (они перезаписываются после каждой завершенной встречи).
Один раз, когда я изменил кол-во денег профиля, как мне показалось, игра скорректировалась и загрузила предыдущий сейв (потому грешу на profile_cld_u).
Мне хотелось бы понять, что из себя представляет profile_cld_u, и как с ним совладать. Я на пикриле некий паттерн байтов, который я заметил, мб в нем магическое число?
P.S Алсо я нашел референсы на profile_cld_u и profile в статических либах, но может пока можно что-то сделать без иды?
Потому что я пока не разбираюсь в ARM
Файлы: http://rgho.st/8sbn2lYwr
Вряд ли без иды что-то сделаешь. Но не нужно смотреть именно дизасм, в IDA есть HexRays, он показывает сишный псевдокод. Просто добавь воды нажми Tab на интересующей функции.
На пике в выделении какие-то явные офсеты (32 бита, little endian), по 0x08 возможно какой-нибудь CRC. Файлы может быть гляну завтра но обещать не буду, если ты сам что-нибудь не накопаешь.
Спасибо, я посмотрю, не знал о такой функции.
Я еще нагуглил 78 da - флаг максимальной компрессии zlib, должно стать полегче)
Там же и интересную вещь нашел:
http://zenhax.com/viewtopic.php?t=27
Теперь с большой вероятностью могу сказать, что это упакованный сейв, но есть некоторые несостыковки
Молодец. Там в .so-шке куча экспортированных символов, так что можно брать иду и смотреть на всякие там CFTTSaveFile::BeginLoadInternal и подобные. Правда, там кресты и виртуальные функции, но даже если с ними не совладаешь, то может имена методов что-то подскажут.
Еба, юзабельно во всяких поделках. Хотя обычно подобные модули на асме пишутся полностью
> во всяких поделках
Винда - поделка. Ну ок.
А так, ты частично прав, соответствующие функции все же чаще пишут на асме (потому что не везде есть так много интринсиков, как в студии), но пишут только тот минимум, который нужен, чтобы потыкать в процессор. Т.е., буквально несколько инструкций.
Может ли приложение узнать читают ли его память?
И кто в этой битве имеет аппер хенд?
Спасибо.
> Может ли приложение узнать читают ли его память?
В целом нет. От приложения с админскими правами и ReadProcessMemory не защититься без драйвера. Но на каждый драйвер тоже можно написать свой драйвер с трюками вплоть до DMA.
> И кто в этой битве имеет аппер хенд?
Никто. При равном уровне привилегий побеждает более хитрая жопа. При различном - тот, у кого привилений больше.
Спасибо.
Вот есть пример кода. Почему все переменные объявляются после кода? Это из-за разделения в досе на сегменты кода и т.п.? Если это так, то как здесь понять, что начинается сегмент данных или я хуйню несу.
Никак. Поскладывай в столбик различные числа и ты поймешь почему так.
Никак он не определяет, это не баг это фича.
Вообще дополнительный код(на твоей пикче это -5) был спецом так разработан, чтобы беспалевно складывать числа без учета их знака и получать всегда правильный результат: для прямого кода - сумму, для дополнительного - разность. То есть с точки зрение проца вычитание это тоже сложение.
> как процессор определяет как ему работать с первым битом
Ему в целом похуй, все зависит от твоей интерпретации этого числа, т.е., от самого кода (и от инструкций - для знакового умножения/делении отдельные инструкции).
>>233436
> Почему все переменные объявляются после кода?
Потому что если их объявить до кода, то процессор начнет их выполнять (в данном случае).
> Это из-за разделения в досе на сегменты кода и т.п.?
В самом досе разделения на сегменты кода и данных нет. Есть просто сегменты. Разделение может существовать в программах (.exe), но твоя программа .com, судя по org 0100h, т.е., она целиком влезает в один сегмент, грузится и начинает выполняться по офсету 0100h (до него лежит PSP). Данные ты можешь положить куда угодно. Можно, например, делать даже так:
org 100h
jmp real_start
foo dw ?
bar dw ?
real_start:
mov ax, 4c00h
int 21h
Лишь бы твои переменные были вне потока выполнения.
Этот код отрабатывает и для жизни мобов. Если я там делаю nop, то я убить не могу никого.
>mov [r9+00000388],r8d
[r9+00000388] это адрес жизни того, кто пострадал. r8d это новое количество HP значит.
Как мне теперь сделать так, чтоб жизнь не отнималась только у моего персонажа?
Это mov надо заменить на jmp в пустое место и там прописать код, который будет проверять:
Если адрес r9+00000388 это адрес жизни нашего персонажа, то ничего не делать. А если чужой адрес, то выполнить mov [r9+00000388],r8d
Да? Или нет?
Сложно пиздец. Нихуя не понимаю.
r8 - 64-битный регистр, r8d - его младшие 32 бита (dword), r8w - младшие 16 бит (word), ну и есть еще r8l - младшие 8 бит. Как rax, eax, ax и al.
Тебе нужно смотреть выше. Видимо, в r10d в первой инструкции кладется индекс персонажа, и для твоего персонажа он скорее всего фиксированный (или его где-то можно узнать). Вот его и проверяй.
>Никто. При равном уровне привилегий побеждает более хитрая жопа. При различном - тот, у кого привилений больше.
Жизненно.
ПАМАГИТЕ и мне, пожалуйста :)
>апи-шпиен керберос
Шо за говно мамонта? Крис конечно хороший парень, но мёртвый писал давно, так что софт нужно гуглить отдельно (кроме иды).
LXI D,02FFH
Start
MVI M,00H
INX H
MOV A,H
SUB D
JNZ Start
MOV A,E
SUB L
JNZ Start
MVI M,00H
HLT
Собственно есть такая вот программа. Если здесь есть очень олдовые чуваки - думаю, узнают. Программа должна обнулять ячейки памяти с адресами от 0100 до 02FF. Проблема в том, что я понимаю как она работает только до 5 строчки.
Собственно непонятки:
Команда MVI M,00H должна помещать значение 00H в регистр М, но что это? В этом процессоре за исключением служебных и двухбайтовых их всего 7 - B C D E F H L.
Команда SUB D должна вычитать из регистра А аккумулятора значение регистра D и помещать результат в А. Уже лучше, но регистр D ранее не появлялся вообще.
Дальше вообще муть. Снова непонятно откуда взявшиеся регистры E и L.
Это программа ебанутая, или я что-то не до конца понимаю?
> Команда MVI M,00H должна помещать значение 00H в регистр М
В данном случае M значит "доступ в память (memory) по адресу (HL)".
> но регистр D ранее не появлялся вообще
Первые две строчки грузят константы в пары HL и DE cоответствено (load extended immediate). И INX там увеличивает не H, а HL. Остальное должно быть понятно. В псевдокод перепиши - разберешься.
Псевдокод..?
Т.е. MVI M,00H записывает во второй байт HL нули, а первый байт - адрес ячейки памяти по команде LXI H,0100H? Как тогда определяется, что операнд команды MVI идет именно в HL?
Дальше. Команды
INX H
MOV A,H
SUB D
JNZ Start
MOV A,E
SUB L
JNZ Start
Прибавляют 1 к текущей ячейке создавая счетчик (в том же байте?), затем номер текущей очищаемой ячейки копируется в аккумулятор, зачем из аккумулятора вычитается адрес конечной ячейки. Если бы я писал это на С, то это был бы цикл if-else с явно видным условием продолжения вычитания (т.е. Goto Start) или же переходом на дальнейшие команды. Но тут этого нет. После вычитания SUB D идет команда JNZ. По идее, тут нужно было как-то задействовать флаг нулевого значения, иначе команда JNZ исполняется всегда. Как тут обстоит дело?
Собственно предположим что я понял/неявным образом флаг работает/особенности обработки кода - короче перепрыгнуло и перешло дальше. Регистр E задействован ранее не был, но я так понимаю, что в нем содержатся младшие биты конечной ячейки 02FF (как мне кажется - т.к. 02FFH = 1011111111B, то 10111111 - 11(000000) - первая часть в D, вторая в E, нули в скобках - автозабивка младших незначащих разрядов). Если это предположение верно, то получается, что переход произошел после того, как H == D, т.е. старшие байты стали равны. Теперь идет сравнение младших по тому же алгоритму.
Последние строчки
JNZ Start
MVI M,00H
HLT
опять радуют JNZ, работающим непонятно как (как и тот, что выше), командой MVI, которая опять непонятно откуда понимает, что теперь нужно забить нулями. Ну хоть команда HLT ясна.
Анончик, я смотрю ты шаришь. Можешь подробнее рассказать про регистровые пары? Откуда я черпаю инфу, про них мимолетом сказано и все.
>По идее, тут нужно было как-то задействовать флаг нулевого значения, иначе команда JNZ исполняется всегда
Бля. Посмотрел что это за команда. Именно это она и делает. Если равно нулю, то исполняется код дальше, если нет - то переход на метку. Перепутал с JMP, списав на разные написания команд для разных процессоров.
>>234440
> Псевдокод..?
Декомпилируй в уме. Пикрелейтед (не текстом, потому что макаба убивает выравнивание).
> Т.е. MVI M,00H записывает во второй байт HL нули
Берет из HL значение, использует это значение, как 16-битный адрес байта в памяти. Кладет туда ноль. Т.е. MOV (HL), BYTE 0.
> Как тогда определяется, что операнд команды MVI идет именно в HL?
Потому что M - признак адресации через HL. Вообще, везде непрямая адресация через HL, кроме стека.
> Теперь идет сравнение младших по тому же алгоритму.
Что-то типа того, да.
> Анончик, я смотрю ты шаришь. Можешь подробнее рассказать про регистровые пары? Откуда я черпаю инфу, про них мимолетом сказано и все.
[soiler]Почти не работал с 8085, так что меня нужно слушать с осторожностью.[/spoiler] А что подробнее? Некоторые инструкции работают с парами регистров, несмотря на то, что указан только старший регистр (или вообще не указан). Вот, например, те, у которых мнемоники с X. Пары BC, DE, HL заранее определены (сделать BD нельзя, например) и ведут себя в этом случае как одно 16-битное значение.
Бля, ну как обычно. Копипаста просочилась, там IF L != E во втором случае. Ну а Z для JNZ ставит SUB, если что.
>Декомпилируй в уме
Ну примерно это я и попробовал сделать.
>Вообще, везде непрямая адресация через HL
Непрямая - т.е. без указания адреса? Адреса нет - значит имелся в виду HL.
>16-битный адрес байта в памяти
Разве MVI - не однобитная команда? Или конкретно тут пох, т.к здесь она используется только до заполнения до 10111111 (первой половиной двоичного 02FF)?
Любая команда вида MVI M,Х - будет задавать число Х в HL? А если надо задать число, не в HL и большее чем 8-бит, то LXI и прямую адресацию на нужную пару?
И как быть, если операнд вмещается в 8 бит? Можно ли отдельно использовать скажем D и E, притом так, чтоб любая операция не влияла на другой регистр скажем, если что-то прибавляется к D, и результат получается больше чем 8 бит - чтоб влияния на регистр E оно не имело, а было переполнение или что-то в этом духе?
Пока что я так понимаю, что они просто как бы склеены между собой, но находятся в памяти отдельно.
Зависит ли время обработки такого спаренного регистра в зависимости от заполненности? Или процессор всегда прогоняет все 16 бит?
И да, разве не нужно обнулять все эти регистры процессора после включения? Там же может что угодно быть. Не зря же на дискретных триггерах есть специальные выводы сброса в 0. Или оно там обнуляется аппаратно?
Адреса памяти, указанные в этой программе, относятся, я так понимаю, к внешней ОЗУ? А вот программа сия по обнулению адресов забивается в ПЗУ, верно?
>8085
Ну, эти команды от 8080, но разницы вроде как нет. Как дойду до чего-то такого, что можно в железе воплотить пусть и в целях мигания светодиодом - скорее всего буду брать процессор 1821ВМ85, который есть суть копия 8085. Но там можно поехать с настройкой ПЗУ, ОЗУ, ввода-вывода, отображением и прошивкой всего этого хлама, который давно пора сдать и купить ардуину парка микросхем.
>>234466
>Ну а Z для JNZ ставит SUB, если что
Ну это я понял. Думал, что JMP и JNZ - одно и то же. SUB вычитает, JNZ проверяет флаг нуля.
>Декомпилируй в уме
Ну примерно это я и попробовал сделать.
>Вообще, везде непрямая адресация через HL
Непрямая - т.е. без указания адреса? Адреса нет - значит имелся в виду HL.
>16-битный адрес байта в памяти
Разве MVI - не однобитная команда? Или конкретно тут пох, т.к здесь она используется только до заполнения до 10111111 (первой половиной двоичного 02FF)?
Любая команда вида MVI M,Х - будет задавать число Х в HL? А если надо задать число, не в HL и большее чем 8-бит, то LXI и прямую адресацию на нужную пару?
И как быть, если операнд вмещается в 8 бит? Можно ли отдельно использовать скажем D и E, притом так, чтоб любая операция не влияла на другой регистр скажем, если что-то прибавляется к D, и результат получается больше чем 8 бит - чтоб влияния на регистр E оно не имело, а было переполнение или что-то в этом духе?
Пока что я так понимаю, что они просто как бы склеены между собой, но находятся в памяти отдельно.
Зависит ли время обработки такого спаренного регистра в зависимости от заполненности? Или процессор всегда прогоняет все 16 бит?
И да, разве не нужно обнулять все эти регистры процессора после включения? Там же может что угодно быть. Не зря же на дискретных триггерах есть специальные выводы сброса в 0. Или оно там обнуляется аппаратно?
Адреса памяти, указанные в этой программе, относятся, я так понимаю, к внешней ОЗУ? А вот программа сия по обнулению адресов забивается в ПЗУ, верно?
>8085
Ну, эти команды от 8080, но разницы вроде как нет. Как дойду до чего-то такого, что можно в железе воплотить пусть и в целях мигания светодиодом - скорее всего буду брать процессор 1821ВМ85, который есть суть копия 8085. Но там можно поехать с настройкой ПЗУ, ОЗУ, ввода-вывода, отображением и прошивкой всего этого хлама, который давно пора сдать и купить ардуину парка микросхем.
>>234466
>Ну а Z для JNZ ставит SUB, если что
Ну это я понял. Думал, что JMP и JNZ - одно и то же. SUB вычитает, JNZ проверяет флаг нуля.
> Разве MVI - не однобитная команда?
Чо? Биты будешь через ANA/ORA/XRA ебать, также их -I версиями и всякими шифтами. А MVI кладет константу, байт в память.
> Любая команда вида MVI M,Х - будет задавать число Х в HL?
Не в HL, а в память по адресу, содержащемуся в HL.
> А если надо задать число, не в HL и большее чем 8-бит, то
Кладешь адрес в HL, делаешь MVI, а если больше 8 бит, то инкрементишь HL и снова делаешь MVI.
> Можно ли отдельно использовать скажем D и E
Конечно можно.
> Или процессор всегда прогоняет все 16 бит?
С чего бы вдруг? С 16-битными парами рабатают специально обученные инструкции.
> И да, разве не нужно обнулять все эти регистры процессора после включения?
Очевидно, что перед тем как читать из регистра (или он неявно как-то используется), туда нужно что-то записать. Если не нужно читать, то не похуй ли тебе, что там лежит?
> Адреса памяти, указанные в этой программе, относятся, я так понимаю, к внешней ОЗУ? А вот программа сия по обнулению адресов забивается в ПЗУ, верно?
Там же вроде общее адресное пространство. Традиционно процессор дрыгает ногами о том, что хочет читать/писать, а уж кто там будет это делать - не его проблемы.
> хлама, который давно пора сдать и купить ардуину
Я бы купил ардуину. Ебаться с древним говном весело, но абсолютно бесполезно. Взял бы 8051 что ли, он хоть используется еще иногда.
Не понимаю, как работает ОС, она умудряется и сама использовать регистры, и остальным прогам дает возможность их использовать. Как не возникает конфликта?
> чем fasm лучше и чем хуже остальных?
Минусы фасма - проблемы с отладочными символами (поддержки стандартных форматов нет и/или она делается внешними утилитами и неполноценная) и то, что он сам написан на x86-асме, и из-за этого запускается только на x86. Если для тебя это не минусы, тогда все ок. Все остальное в фасме - плюсы.
> Хочу научиться в будущем пилить красивые демки
Раз умеешь в 16-битный код - можешь уже начинать. Mode 13h, прямой доступ к видеопамяти, вот это все.
>>234490
> Как несколько программ одновременно могут использовать одни и те же регистры?
Вытесняющая многозадачность же. В один момент времени работает только какой-то один поток. Ядро ОС вешается на прерывание таймера. Когда оно срабатывает, процессор при передаче управления обработчику прерывания сохраняет некоторые регистры (на x86 в стек, на ARM в SPSR). Код обработчика прерывания в ОС сохраняет остальные регистры до того, как начинает использовать их для своих нужд. После этого регистры копируются в структуру, хранящую состояние (контекст) потока. Потом выбирается по какому-нибудь алгоритму другой поток, готовый к исполнению (т.е., не ожидающий какого-то события - например, завершения чтения данных с диска). Переключаются таблицы страниц на таблицы страниц выбранного потока, сбрасываются всякие кэши, происходит много другой магии, и, наконец, из контекста этого потока читаются его регистры, происходит возврат из прерывания, и вот уже этот поток как ни в чем не бывало выполняет свой код с того места, где его прервали в прошлый раз.
По-настоящему одновременно программы могут работать только на многоядерном процессоре, но так как ядер обычно меньше, чем потоков, то механизмы вытесняющей многозадачности никуда не деваются и там.
> она умудряется и сама использовать регистры
Во всех точках входа в ядро текущие значения регистров сохраняются, при выходе из ядра - восстанавливаются.
То есть, с какой-то определенной частотой я правильно понимаю прерывание таймера?, система сохраняет в своем стеке или где-то там еще регистры процесса, который она выполняла, и переходит на другой процесс, а процессы в состоянии ожидания не трогаются до тех пор, пока не дожидаются выполнения события, так?
виртуальная адресация
>Чо? Биты будешь через ANA/ORA/XRA ебать, также их -I версиями и всякими шифтами. А MVI кладет константу, байт в память.
Бл. Разумеется, я имел в виду однобайтовая, а не однобитовая.
>Не в HL, а в память по адресу, содержащемуся в HL.
А если нужно скопировать двухбайтовое значение из HL в другую пару? MOV - однобайтовая, а среди двухбайтовых команд аналогичной что-то я не вижу - либо обмен, либо пересылка в стековый регистр.
>> А если надо задать число, не в HL и большее чем 8-бит, то
>Кладешь адрес в HL, делаешь MVI, а если больше 8 бит, то инкрементишь HL и снова делаешь MVI.
LXI H, 0001H
MVI M, 25D
INX H
MVI M, 26D
Получится 11001(000)-11010(000)? И какие будут адреса памяти использоваться, 0001Н и 0002Н? Но это в HL же ведь. Как это чудо потом переслать в другую пару?
>Очевидно, что перед тем как читать из регистра (или он неявно как-то используется), туда нужно что-то записать. Если не нужно читать, то не похуй ли тебе, что там лежит?
Так-то похуй, но по-хорошему, нужно делать это или нет?
>Там же вроде общее адресное пространство. Традиционно процессор дрыгает ногами о том, что хочет читать/писать, а уж кто там будет это делать - не его проблемы.
Ясно. Там уже мелочи - скорее всего, в пространство, отведенное ПЗУ, процессор писать ничего не может.
>Ебаться с древним говном весело, но абсолютно бесполезно
Ну, ископаемые микропроцессорные комплекты обладают двумя достоинствами. Во-первых, по ним много информации, в т.ч. и на русском языке. Во-вторых, сделать на них что-то работающее проще, чем на современных МПК ну тут спорно, т.к. все зависит от того, что необходимо. Йоба-игоры с таким-то графоном, разумеется, не про 8080 серию. Интересно было бы глянуть, на чем делаются современные лабораторные приборы, наверняка там управление идет через какой-нибудь МК или процессор.
>Чо? Биты будешь через ANA/ORA/XRA ебать, также их -I версиями и всякими шифтами. А MVI кладет константу, байт в память.
Бл. Разумеется, я имел в виду однобайтовая, а не однобитовая.
>Не в HL, а в память по адресу, содержащемуся в HL.
А если нужно скопировать двухбайтовое значение из HL в другую пару? MOV - однобайтовая, а среди двухбайтовых команд аналогичной что-то я не вижу - либо обмен, либо пересылка в стековый регистр.
>> А если надо задать число, не в HL и большее чем 8-бит, то
>Кладешь адрес в HL, делаешь MVI, а если больше 8 бит, то инкрементишь HL и снова делаешь MVI.
LXI H, 0001H
MVI M, 25D
INX H
MVI M, 26D
Получится 11001(000)-11010(000)? И какие будут адреса памяти использоваться, 0001Н и 0002Н? Но это в HL же ведь. Как это чудо потом переслать в другую пару?
>Очевидно, что перед тем как читать из регистра (или он неявно как-то используется), туда нужно что-то записать. Если не нужно читать, то не похуй ли тебе, что там лежит?
Так-то похуй, но по-хорошему, нужно делать это или нет?
>Там же вроде общее адресное пространство. Традиционно процессор дрыгает ногами о том, что хочет читать/писать, а уж кто там будет это делать - не его проблемы.
Ясно. Там уже мелочи - скорее всего, в пространство, отведенное ПЗУ, процессор писать ничего не может.
>Ебаться с древним говном весело, но абсолютно бесполезно
Ну, ископаемые микропроцессорные комплекты обладают двумя достоинствами. Во-первых, по ним много информации, в т.ч. и на русском языке. Во-вторых, сделать на них что-то работающее проще, чем на современных МПК ну тут спорно, т.к. все зависит от того, что необходимо. Йоба-игоры с таким-то графоном, разумеется, не про 8080 серию. Интересно было бы глянуть, на чем делаются современные лабораторные приборы, наверняка там управление идет через какой-нибудь МК или процессор.
Именно так.
>>234715
> А если нужно скопировать двухбайтовое значение из HL в другую пару?
> команд аналогичной что-то я не вижу
Ну кроме обмена и PUSH/POP ты можешь просто сделать:
MOV B,H
MOV C,L
> Получится 11001(000)-11010(000)?
Что за нули в скобках? Да, по адресам 1 и 2 в памяти будут значения 25 и 26. Мы, видимо, не поняли друг друга. Зачем в другую пару? Или ты имел в виду, как 16-битное значение в регистровую пару положить?
> А если надо задать число, не в HL и большее чем 8-бит, то
Ну так LXI B,1234H и LXI D,ABCDH.
> но по-хорошему, нужно делать это или нет?
А мне-то откуда знать?
> процессор писать ничего не может.
Будет или какой-нибудь фолт (есть в 8080 bus error?), или запись проигнорируется.
>Что за нули в скобках?
Имелось в виду да, как поместить число в пару.
Нули - незначащие старшие разряды. Вернее, кстати, должно быть 00011001-00011010.
Получается, что в таком случае в паре HL байт H будет по адресу 1, а байт L - по адресу 2?
> Получается, что в таком случае в паре HL байт H будет по адресу 1, а байт L - по адресу 2?
Чо? Мы про это ведь?
> LXI H, 0001H
> MVI M, 25D
> INX H
> MVI M, 26D
MEM[HL] = 25
MEM[HL + 1] = 26
Где ты здесь видишь БАЙТЫ H и L?
Память же у него восьмибитная? Если так, то регистровая пара должна записываться в два адреса, как они задаются? Командами
LXI H, 0001H
MVI M, 1337D
вписывается в пару, но по каким адресам будут расположены байты H и L?
>> LXI H, 0001H
>> MVI M, 25D
>> INX H
>> MVI M, 26D
Здесь надо записать в H одно число, а в L - другое. Правда я хуйню написал, т.к. работать оно похоже не будет. Как это сделать? И опять же, вопрос про конкретные адреса в этом случае в силе.
думаю на этом пока что прекращу, дальше хоть чуть сам попробую разобраться
> MVI M, 1337D
Тебе скажут, что immediate is out of range. MVI пишет восьмибитное значение, 1 (один) байт по адресу, составленному из значений HL (т.е., по H 256 + L). 1337 в один байт не влезает.
> по каким адресам будут расположены байты H и L?
Ни по каким, они указывают назначение, а не источник.
MVI M,123D -> MVI (HL), 123D -> MEM[HL] = 123D -> MEM[H 256 + L] = 123D
> Если так, то регистровая пара должна записываться в два адреса
Здесь не пишется регистровая пара. Если бы мы говорили о какой-нибудь SHLD addr, которая пишет по указанному константному адресу содержимое HL (store HL direct), то сначала (по addr+0) пишется L, потом (по addr+1) пишется H.
> Здесь надо записать в H одно число, а в L - другое.
Здесь ты пишешь в память. Мы уже целые сутки об этом говорим. LXI грузит в H и L указанную 16-битную константу (если взять LXI H, ABCDH, то оно делает H = AB, L = CD). MVI пишет 8-битную константу в память по адресу, который берет из HL.
> И опять же, вопрос про конкретные адреса в этом случае в силе.
Какие адреса? Чего именно?
>сначала (по addr+0) пишется L, потом (по addr+1) пишется H
Собственно вопрос про адреса заключался в этом.
Но не наоборот ли? HL же, по идее должна H быть перед L.
>> по каким адресам будут расположены байты H и L?
>Ни по каким, они указывают назначение, а не источник.
А это со времен писания программ на С. Задал переменную - и не имеешь-в-виду мозги, свои и чужие. Тут же регистр просто определяет, из какой ячейки памяти взять данные и куда их отправить ведь так?
>MVI M,123D -> MVI (HL), 123D -> MEM[HL] = 123D -> MEM[H 256 + L] = 123D
Команда -> полная запись -> память по адресу HL принимает значение 123D -> ???. Записанное в ячейке H × 256 + L число = 123D?
Но откуда такая запись - H × 256 + L?
> Но не наоборот ли?
Не наоборот. Там little-endian.
> Записанное в ячейке H × 256 + L число = 123D?
MVI пишет 123 в эту ячейку.
> Но откуда такая запись - H × 256 + L?
Ну так мы уже выяснили, что два 8-битных регистра H и L соединяются в один 16-битный. Естественно, в процессоре ничего не умножается физически, там гейты, но значение HL можно получить сдвигом H влево на 8 бит и заполнением младших 8 бит битами L. Можно записать как H << 8 | L. Можно заменить сдвиг умножением на 256 (256 = 28), а так как после умножения или сдвига в младших битах по определению нули, то | можно заменить сложением.
>Ну так мы уже выяснили, что два 8-битных регистра H и L соединяются в один 16-битный. Естественно, в процессоре ничего не умножается физически, там гейты, но значение HL можно получить сдвигом H влево на 8 бит и заполнением младших 8 бит битами L. Можно записать как H << 8 | L. Можно заменить сдвиг умножением на 256 (256 = 28), а так как после умножения или сдвига в младших битах по определению нули, то | можно заменить сложением.
Я так понимаю, такая запись должна иллюстрировать взаимосвязь H и L, процесс их слияния? Тогда почему регистр H сдвигается влево (т.е. на один адрес памяти в минус), когда
>сначала (по addr+0) пишется L, потом (по addr+1) пишется H.
Это только от тебя зависит, от твоего желания и стремления.
>Тогда почему регистр H сдвигается влево (т.е. на один адрес памяти в минус), когда
Какие адреса вообще? Влево - это не в памяти. Мы говорим о битах. Влево - это в битах. Биты нумеруются справа налево, от менее значимых младших к более значимым старшим. И поэтому биты H (hi) попадают в старшие 8 бит 16-битного значения, а биты L (lo) - в младшие. Ты бы что ли какого-нибудь Петцольда почитал.
>>235289
> кажется она на правленном движке первого старкрафта
Будет не очень приятно, c DirectDraw-то.
В общем и целом, если ты C/C++ знаешь, то можешь попытаться поковырять, только не дизассемблерный листинг, конечно, а в HexRays. Получится или нет - зависит от архитектуры приложения. Например, оно может физически не уметь рисовать больше N юнитов на экране, и с маленьким разрешением до лимита не доходить, а с большим - превышать его в разы. И чтобы подобные проблемы фиксить, может понадобиться очень много всего перепилить. А просто выставить разрешение повыше у экранных поверхностей и запустить без вылетов - это самая меньшая из проблем.
Возник вопрос, зачем перед вызовом процедуры?
>SetCursorPos:
> mov ah,2h
> xor bh,bh
> int 10h
> ret
Перемещается в dx нуль?
>mov dx,0h
>call SetCursorPos
*с ret в конце
>процедуры - это метки что ли простые в ret в конце?
Типа того, только с соглашением о вызовах, если они библиотечные. А инструкция call всего лишь адрес возврата в стеке сохраняет, а ret его востанавливает в счетчик адреса команд.
.386p
.model flat, stdcall
extrn GetModuleHandleA@4:proc
includelib kernel32.lib
.data
imagebase dd 00400000h
.code
start:
int 3
mov edx, [imagebase]
mov eax, [edx + 3Ch]
add eax, edx
mov ebx, [eax + 80h]
add ebx, edx
end start
Если оставить extrn GetModuleHandleA@4:proc, программа падает при запуске с ошибкой 0xC0000045. Если закомментить - запускается, но падает, поскольку таблица импорта не создается. Откуда ошибка 0xC0000045?
Как хочешь. Для высокоуровневых языков есть соглашения о вызове, а на асме ты можешь хоть все регистры параметрами засрать.
> Возник вопрос, зачем перед вызовом
> процедуры? Перемещается в dx нуль?
Потому что пикрелейтед.
>>236270
Может быть, дело не в импорте, а в том, что у тебя программа после add ebx,eax идет выполнять мусор?
>>236463
Мы знаем. Потому что суть компилятора в оптимизациях, а оптимизировать что-либо, когда код напрямую ебет регистры, почти невозможно. Даже без этого правильно выбрать регистры под переменные оптимизатору очень непросто. Алсо, в Си было ключевое слово register, которое тоже портило жизнь и практически во всех компиляторах есть инлайн-асм, из которого ты можешь работать с регистрами, если тебе это зачем-то понадобилось.
Очень древний хелп откуда-то. До меня дошло как "Assembly Language.ng" с досовым вьювером. Но на скринах открыто во вьювере Expert Guide for Windows. Могу выложить.
Все, что было (там еще Ralf Brown кривой и еще что-то): https://transfer.sh/JacKp/NG.zip
Вьювер: http://davep.org/norton-guides/
>>236496
> Сейчас разве нет?
Сейчас ключевое слово есть, но все, что оно делает - это запрещает применять к переменной оператор &. Большинство компиляторов не учитывает register даже как хинт для оптимизаций.
>Все, что было (там еще Ralf Brown кривой и еще что-то): https://transfer.sh/JacKp/NG.zip
>Вьювер: http://davep.org/norton-guides/
Благодарствую.
>https://beginners.re/ - "Reverse Engineering для начинающих"- бесплатная современная книга на русском языке. К прочтению вкатывающимся и прочим ньюфагам обязательна!
Вот начал я её читать. И нихуя она не для начинающих. Там так всё пиздецово завёрнуто и не объясняются элементарные основы. Что такое стек, регистр, куча всяких понятий, которые ньюфагу нихуя не понятны и понятны быть не могут.
Есть что-то, что реально для начинающих?
Ну найди себе книжку про ассемблер для начала тогда. Или какого-нибудь Петцольда (Код, тайный язык информатики) почитай, например.
>Что такое стек, регистр
Ты даун даже в чтение не можешь
>Желательные знания перед началом чтения
>Очень желательно базовое знание ЯП 9 Си. Рекомендуемые материалы: 11.1.3 (стр. 987)
Берёшь и переходишь на эту страницу и читаешь все книги, что там перечислены. Для начала хотя бы оглавления осиль.
>Что такое стек, регистр, куча всяких понятий, которые ньюфагу нихуя не понятны и понятны быть не могут
Тебе, долбоебу, и не нужно знать что такие регистр и стэк. Надо знать правила их использования и где это приемлемо.
Например у меня есть маленькая программка, и мне надо в ней изменить одну инструкцию на другую (Например с inc на dec), ебаться с кодами операций нету желания.
А не чего по минималистичней нету? Не очень кайфого юзать отладчик для изменения одной команды
python+capstone+keystone, ida умеет код патчить, в нее же можно keystone завезти. Хуй знает, что тебе нужно и зачем.
>Ну. В нулевом кольце интринсики запрещены законом, или что?
Так получается это сисколл. Им можно поменять любой флаг в cr-ках?
Это интринсик. Выглядил как функция, квакает как функция, а компилируется в одну или несколько ассемблерных инструкций. Поэтому с одной стороны у тебя чистый сишный код без асм-вставок, а с другой стороны ты можешь получать доступ к низкоуровневым возможностям, которых в Си нет. Алсо, существуют интринсики, которые разворачиваются в тот набор инструкций, который поддерживается целевым процессором - в основном это SIMD и всякая байто- и бито-ебля, которая есть везде, но в Си напрямую не поддерживается.
>>240925
Не, я не про это, понятно что это функция, просто из юзеспейса нельзя напрямую менять регистр cr, только через нулевое кольцо, а это значит вызов сискола. Ну просто же нальзя взять и изменить просто cr регистр из 3ого кольца. Т.е. получается только через сискол, если в контексте венды.
> Ну просто же нальзя взять и изменить просто cr регистр из 3ого кольца.
Значит тебе прилетит исключение, вот и все. Никаких сисколов.
Да мы тебе на ебальник ссали, защекан. Пиздуй юзать то, что есть, не выебывайся.
>Сейчас ключевое слово есть, но все, что оно делает - это запрещает применять к переменной оператор &. Большинство компиляторов не учитывает register даже как хинт для оптимизаций.
И тут GCC на высоте если делать ассемблерные вставки:
https://gcc.gnu.org/onlinedocs/gcc/Explicit-Register-Variables.html
Для битхака - HIEW и HT. Для средних и больших патчей - FASM с макросами от Grom PE (ищи сам на форуме фазма).
> OllyDbg
Спасибо, попробую, конечно, но с турбо дебаггером все равно, мне кажется, по незамысловатости не сравнится. Но это я говорю, увидев скриншоты, так что хуй знает.
Под виндами x64dbg и OllyDbg, под досом SoftICE, под макосью LLDB и GDB.
Я имел ввиду, куда конкретно.
Держи вкурсе.
Как? Давай подробнее...
Сам подумай
> нахуя вы ебетесь с асмом
Помогает при отладке объяснить любую, даже самую удивительную магию, происходящую в коде. В том числе и в чужом коде. В том числе и без исходников.
> работа, требующая знание асма и приносящая хороший доход
Есть embedded (писать на асме не нужно, а вот понимать происходящее крайне желательно). Теоретически есть реверсинг, но с доходами там туго.
Дает понимание работы ОС и программ в целом. Я вообще линупс одмин, а изучаю реверс для фана, ибо интересно.
> запускается только на x86
fasmarm написан на x86-асме, а компилирует в ARM. И он уже не нужен после выхода fasmg. Ты не можешь взять малинку, текстовый редактор и писать на фасме. Тебе придется взять пеку и компилировать на нем на самом деле можно qemu, но это, тем не менее, весьма неудобно.
Есть ли способ сразу прийти к тому состоянию, что бы сходу впитывать в себя новые знания, ведь они потом все равно будут тебе казаться элементарными и логически последовательными. Надеюсь кто нибудь поймет что я имел в виду.
чем больше технологий изучишь, тем будет проще понимать "сходу"
Ну у меня есть неортодоксальный взгляд на эту тему. Просто дело в том что 99.99% объяснений (особенно если брать те которые попадаются при беглом знакомстве с темой) беспросветная чушь, и автар их писавший - терминальный мудило. Но рано или поздно ты находишь нормальное объяснение и автор его писавший - няша, либо у него была минута озарения. И ты внезапно понимаешь то что так давно не мог понять.
Утро вечера мудренее.
Без контекста непонятно, показывай исходник.
Скорее всего там просто ожидаемый результат из-за оптимизации.
Исходника нет, ковыряю чужую программу. На предмет излечения от жадности. На оптимизацию как-то совсем не похоже, на naked функцию тоже - внутри функции вызывается operator new [], да и код, за исключением следования непонятному соглашению о вызове, выглядит как типичный выхлоп компилятора.
http://bitfry.narod.ru/ Тут только начало, и как я понял должно быть продолжение.
Это как-то связано с пикрелейтедом, но чтобы разобраться точнее, нужно смотреть остальной код.
Ты охуенен, анон. Очень похоже, что это оно и есть. Буду разбираться дальше.
10110111100b = 1468d ( согласно калькуляторам). Если посчитать вручную на листике, то :
10110111100 = 110^10+ 010^9+ 1*10^8 etc ПОЛУЧАЕТСЯ
10110111100b = 10110111100d ?????????????????????????
Боты вы здесь? Агенты Смиты?
Идем дальше.
10110111100b = 5BCh
5BCh = 1468d
1468d = 10110111100b
10110111100b ≠ 1468d
Что это за хуйня аноныагенты Смиты?
Не переживай, мы все равно нихуя не поняли.
Да, действительно.
Это ты конечно сильно обосрался.
странно, в шапке не нашел.
первая ссылка на архив пока что еще доступна на веархиве. задублируйте что ли
>>Все имеющиеся у меня материалы Криса (более 450 статей и книг) собраны в одном архиве:
>>www.insidepro.com/download/KK.zip
>>Для работы необходимо распаковать архив и запустить файл Index.html.
>>Несмотря на то, что все статьи были написаны достаточно давно, каждый сможет там найти что-нибудь интересное для себя и это будет хорошей памятью о человеке, который в свое время был настоящим хакером (в истинном смысле этого слова - пытливым, эрудированным, многогранным и с феноменальной работоспособностью).
>>-----------------------------
>>И сразу небольшой дисклеймер:
>>1. Все эти материалы накоплены лично мной за несколько лет и ниоткуда не скопированы.
>>2. Статьи Крис присылал сам (или давал доступ к своему фтп-серверу) и было его полное согласие на публикацию на сайте всех этих материалов.
>>3. Многие статьи были в рабочем или неоконченном состоянии, поэтому могут содержать ошибки, неточности или несоответствия по сравнению с журнальными вариантами.
>>4. Все эти материалы ранее выкладывались на сайте в разделе "Библиотека" (с 2010 по 2014 год):
>>http://web.archive.org/web/20140227133549/http://www.insidepro.com/rus/doc.shtml
>>5. На старом форуме WASM.ru Крис неоднократно сам упоминал сайт InsidePro и давал ссылку на него как на самый большой архив с его публикациями (и может оказаться так, что сейчас это действительно самый полный архив с его статьями на русском языке).
>>-----
>>EnJoy!
Не может. Поэтому там упомянут x64dbg, интерфейс которого на 3/4 спизжен с ольки (правда, криво).
хотя оплазил по рутрекеру, вот есть сборник чисто только статей. https://rutracker.org/forum/viewtopic.php?t=5375505
c = cc > 0 ? cc : -cc;
Сейчас сделано так, но остаётся установленным carry-flag.
Добавлять clc в каждую asm-функцию не хочется, какие варианты?
Собственно, вопрос. Почему? После инвертации битов carry не стоит. Если потом к "с" прибавить 1, то carry всё ещё не стоит, там небольшое число.
Но вся конструкция целиком устанавливает carry. Какого хуя?
c = cc > 0 ? cc : (~cc)+1;
CF raised
if(cc > 0) {
c = cc;
} else {
c = ~cc;
c++;
}
CF not raised
Какой нахуй CF в сишном коде? Ты там под конкретную версию компилятора пишешь? А если в следующей оптимизатор изменится? А если у тебя флаги изменятся? А если в твоем коде что-то изменится, даже не относящееся к твоей функции, но косвенно влияющее на оптимизатор?
Ну, не под конкретную версию, но пока что у меня вполне конкретный определённый gcc.
Пишу на asm/c, clc у меян в функциях не было, так как на сишке у меня нет математики, она на асме, вот я и не ожидал такой подставы.
Какое решение в итоге? Иметь clc в начале каждой математической функции, которая может зависеть от CF, так как полагаться на то, что флаг не установлен - просто нельзя?
> Иметь clc в начале каждой математической функции, которая может зависеть от CF
Я бы даже в асме за такое по голове стучал. Даже как true/false для bool func() CF часто неудобен, а уж как аргумент его использовать - это вообще пиздец. Если у твоей функции есть параметр carry (хотя я сходу не смог придумать функции, где такое понадобилось бы) - передавай его в регистрах или в стеке. Нахуя тебе clc, я вообще не понял. Пример приведи. Если у тебя, допустим, длинное сложение, ты начинаешь с add, продолжаешь adc - никаким местом от изначального CF оно не зависит.
Сколько они реально занимают места?
Применяется ли к памяти, занимаемой ими, страничное преобразование?
Ядро самой ОС работает в страничной памяти?
Абстракции, абстракции, абстракции. Без них невозможно удобно и быстро решить множество прикладных задач. Тебе так или иначе придётся создать какой-то инструмент, который позволяет инкапсулировать реальные процессы, протекающие в полупроводниковых элементах в
А, блядь, я даже не понимаю сам, о чём я говорю. Я знаю, что без абстракций нельзя, но почему внятно объяснить не могу.
А вообще, где почитать про то, как на аппаратном уровне реализуются все эти механизмы поддержки защищённого режима и многозадачности? И вообще про теорию производства микроконтроллеров и микропроцессоров, с диаграммами и принципиальными электронными схемами их устройства.
Ну и ВООБЩЕ ВООБЩЕ, откуда все эти интеловские микроэлектронщики получают свои скиллы? Есть же какая-то дисциплина, какие-то учебные пособия по теме, в которых говорится "Вот смотри, вот сюда транзистор, сюда транзистор и сюда ячейку памяти, вот у нас будет таймер. А вот так, вот так и вот так, это у нас элемент "И". А вот так, так, так, и так и вот у нас тридцатидвухразрядный мультипликатор действительных чисел, со встроенной возможностью поразрядной проверки делимости результата на степени пяти"?
Нашел! HTE назвается
> Где реально располагаются каталоги таблиц страниц и сами таблицы страниц?
В оперативной памяти (ну еще кэш TLB в проце).
> Сколько они реально занимают места?
Зависит от архитектуры, структуры таблицы страниц, размера дескриптора страницы, размера страницы и количества доступной памяти - чем больше у тебя страниц, тем больше места занимают таблицы.
> Применяется ли к памяти, занимаемой ими, страничное преобразование?
Если тебе нужно. Но в MMU кладется физический адрес, и в случае многоуровневых таблиц MMU тоже по физическим адресам ходит.
> Ядро самой ОС работает в страничной памяти?
Выключать преобразования долго, да и незачем, поэтому да.
>>249211
> А вообще, где почитать про то, как на аппаратном уровне реализуются все эти механизмы поддержки защищённого режима и многозадачности?
Таненбаум "Современные ОС", мануал на интересующий процессор.
> И вообще про теорию производства микроконтроллеров и микропроцессоров
Паки в поисковиках по BitTorrent DHT: digital systems design, computer architecture. В них овердохуя книг, ну или отдельно Хеннесси/Паттерсоны, Харрисы всякие. Можешь вот индусов еще посмотреть, если акцент не смущает: что-нибудь подобное https://www.youtube.com/playlist?list=PL59E5B57A04EAE09C (и вообще плейлисты на этом канале, там есть и уровнем ниже - про электронику, и уровнем выше - про архитектуру).
> вы для своих изысканий пробовали использовать виртуальные машины типа Bochs
Если с правилами - тебе лучше что-нибудь для инструментирования взять - DynamoRIO, Intel PIN там, ну или даже просто Unicorn Engine (хотя у единорога апи максимально уебищный и не годится ни для чего серьезного).
сажа отвалилась
Вообще молодца, огромное спасибо.
К примеру, насколько сильно отличается создание программ для процессоров с суперскалярным конвейером от процессоров с, ну, обычным?
Намного. Ебать x86 ассемблер в 2кХХ имеет смысл только для реверсинга/нелегального патчинга бинарников и малвари. Для всего остального есть интринсики и другие языки.
>Для всего остального есть интринсики
Мне не понравилось, неудобно.
Пишу на Си+ASM разную математику.
Анон с соседнего треда пояснил, что оно натыкается на два nop'a и исполняет дальше, где уже и защищенные области памяти. Почему так происходит? Ведь выделено памяти лишь под sizeof(code);
https://ideone.com/ZtKovP
include "huinya32.INC"
include "govno32.INC"
include "ssanina/vrotebal32.INC"
nevedomaya magiya, v, makrosah
pizdec ebal, eti, makrosi
В этих ебучих inc-файлах не разобрался, что к чему. Неужели нельзя написать простую 32-битную программку без упрощений ввиде макросов? Где прочитать доходчивое объяснение того, как эта залупа работает? Строится ли все это на основе, ввиде прерываний, или тут какой-нибудь windows api и работает это не так, как дос-программы?
Ну смотри. Макросы можно и не использовать. Но: тебе нужны константы, в винде их дохуя, ты заебешься смотреть численные значения для каждой, тебе нужны структуры, в винде их дохуя, и ты заебешься вычислять офсеты. Конкретно без proc и invoke жить можно без проблем.
> Где прочитать доходчивое объяснение того, как эта залупа работает?
В документации.
> Строится ли все это на основе, ввиде прерываний
Прерывание всего одно - int 2e, хотя вместо него сейчас используется sysenter на процессорах, которые это умеют (читай: везде). Но номера сервисов для этого прерывания меняются от винды к винде, от билда к билду, поэтому напрямую системными вызовами пользуются только некоторые протекторы (у них там таблички), а для людей это все обернуто в API-функции. Вот эти функции, а также кучи других, более высокоуровневых, ты и вызываешь. Весь твой invoke сводится к push-push-push аргументов и call dword[SomeAPI]. Через некоторое время почитаешь про то, как работают DLL. Больше в программировании под винду для начинающих ничего сложного нет, да и вообще, писать под DOS гораздо сложнее.
Если что-то не понимаешь, приходи с конкретными вопросами про конкретную nevedomaya magiya-нейм.
Сами API-функции - в .dll, а конкретно тот дворд, который ты в call суешь (SomeAPI dd ?) - у тебя в таблице импорта. При загрузке твоей программы лоадер PE с помощью магии и извращений кладет туда адрес функции.
То есть это 32-битное значение - это адрес, по которому в конкретном длл-файле находится функция, так?
Это адрес, по которому загрузчик эту функцию поместил при загрузке dll и пометил для операционной системы, что такие-то функции (имя функции аски-текстом) он скопировал туда-то в оперативу (DWORD адрес на 32 бит, QUADWORD адрес на 64).
Вызывая функцию GetProcAddress и передавая в неё указатель на с-строку с именем функции (буквами) ты в ответ получаешь указатель на неё или 0 если такой функции нет. Либо то же самое делается под капотом если у тебя статическая линковка через вспомогательную lib - в таком случае этот код компилятор написал за тебя и вызовется он автоматом.
Вообще, нужно понимать, что исполняемые файлы при компиляции делаются перемещаемыми - в них компилятор для всего кода использует относительную от каких-то подставляемых значений адресацию, а загрузчик при загрузке исполняемого файла эти значения подставляет и код работает.
> ты в ответ получаешь указатель на неё
Адрес относительно какого-то сегмента, или прямой адрес, указывающий на какую-то точку памяти?
> или 0 если такой функции нет
А что, если функция находится по этому адресу? Или такое невозможно?
Много вопросов, прошу прощения.
>А что, если функция находится по этому адресу? Или такое невозможно?
Такое невозможно и в большинстве архитектур переход на 0 вызывает исключение ошибки выполнения
> Адрес относительно какого-то сегмента, или прямой адрес, указывающий на какую-то точку памяти?
Адрес виртуальной памяти. Сегмент в защищенном режиме у тебя всегда один (тут есть пара ньюансов касательно 32-разрядного режима и 0 кольца (операционной системы), но для юзермода считай что сегментов нет), модель памяти плоская, виртуальное адресное пространство непрерывно, но сразу не доступно - если обратишься по какому-то адресу и там страница не отображена - то получишь сегфолт (да, он так называется по рудиментарным причинам из ранних шиндошс, на самом деле происходит ошибка табличной адресации).
В защищенном режиме адреса всегда виртуальные, даже для операционной системы. Трансляция адресов производится операционной системой через таблицы страниц - единственное место где в защищенном режиме упоминаются физические адреса.
Охуеть ты классный
> но для юзермода считай что сегментов нет
Напомню про fs/gs. Напомню, что в cs и ds разные селекторы.
> получишь сегфолт
С линуксами путаешь, в винде нет сегфолтов, есть STATUS_ACCESS_VIOLATION.
> переход на 0 вызывает исключение ошибки выполнения
Это не особенность архитектуры. В большинстве архитектур нормально начинать выполнение с 0. В x86 это тоже возможно. Ошибка исполнения возникает потому, что по 0 ничего не выделено.
>>254090
> А что, если функция находится по этому адресу?
Первые 64к адресного пространства у юзермодных приложений недоступны, даже если ты специально захочешь там что-либо выделить (в предыдущих версиях винды иногда можно было, в линуксе с админскими правами и сейчас можно: https://ideone.com/ps88Rb). В основном это сделано для того, чтобы отлавливать доступ по нулевым указателям, в том числе и в массивы (array[n], когда array == NULL). Если ты таки сумел выделить что-то в первых 64к, зарегистрировать это в лоадере как длл и заставить GetProcAddress вернуть NULL для существующей функции - ты сам себе злобный буратино.
А в каком смысле перемещаемыми? Можно изменить расположение кода в оперативной памяти? Или имеется ввиду, что их можно перемещать из каталога в каталог? Тогда чем COM, например, не перемещаемый?
Я где-то слышал что в 0 специально ничего не выдяляют, для типа NULL , если разыменовать указатель, то возникает как раз исключение, но то уже в контексте Си.
>cs и ds разные селекторы.
Т.е. Выделяются два сегмента для кода и данных? а стек? Поему не сделали плоскую чтобы cs=ds=ss=fs=gs ?
> Я где-то слышал что в 0 специально ничего не выдяляют
Ну я об этом и написал. На Си и крестах по-прежнему написано овердохуя кода (если не приложения, то библиотеки), поэтому отсутствие памяти по 0 - часть дизайна любой ОС, которая такой код выполняет.
> Выделяются два сегмента для кода и данных?
Да.
> Поему не сделали плоскую чтобы cs=ds=ss
Фактически она плоская (т.е., базы-лимиты совпадают). Селектор cs != селектору ds по всяким связанным с x86 причинам: например, в сегмент кода нельзя писать, по этому поводу для когда приходится делать отдельный дескриптор.
> fs/gs
Используется для быстрого доступа к TEB/PEB (например, для thread-local переменных или для обработки исключений), сегментный регистр позволяет каждому потоку быстро находить свои данные без системных вызовов или каких-то хитровыебанных вычислений адреса. В дескрипторах сегментов лежит ненулевая база.
Получается что сегментые регистры не меняются, ос меняет только cr3 при переключении контекста?
>Можно изменить расположение кода в оперативной памяти?
Ну, менять расположение уже загруженного кода смысла особо нет, но можно изначально загружать код каждый раз в рандомные места виртуальной памяти и делать ему глобальные переменные и стек тоже в рандомных местах. Так ASLR работает, к примеру.
На вики написано, что все смещения, вроде как, записаны относительно предпочитаемого базового адреса, а загрузчик эти значения пересчитывает, если нужно записать программу в другую точку в памяти. Зачем это? Не проще вместо линейного адреса записать относительный адрес, чтобы не приходилось ничего пересчитывать. Я, скорее всего, чего-то не понимаю, но звучит это как какой-то маразм.
>Не проще вместо линейного адреса записать относительный адрес, чтобы не приходилось ничего пересчитывать.
Относительные адреса ограничены, емнип, 32 битами и только для JMP, у MOV вариантов с относительной адресацией нет, а счетчик команд читать нельзя. Поэтому и изменяемые базовые адреса и абсолютные смещения от них.
> Относительные адреса ограничены, емнип, 32 битами и только для JMP
Да, и именно этот механизм используется в ДЛЛ.
> у MOV вариантов с относительной адресацией нет, а счетчик команд читать нельзя. Поэтому и изменяемые базовые адреса и абсолютные смещения от них.
Есть хак:
JMP nextline
nextline:
pop ebx
>>254561
То что описал >>254534 анончик называется load-time relocation и это действительно стандартный встроенный механизм загрузки исполняемых файлов - exe и elf по своей структуре заточены именно под него.
То что ты описал называется position-independent code
и этот подход сейчас тоже активно применяется и компиляторы в него умеют.
вот статья:
pop ebx
> То что ты описал называется position-independent code
> и этот подход сейчас тоже активно применяется и компиляторы в него умеют.
Только ты забыл сказать, что оно жрет регистр, которых в 32-битном коде и так мало (в 64-битном коде уже есть нормальная и rip-relative адресация, и регистров там достаточно), плюс PIC чаще всего требует лишнего дереференса, поэтому медленнее, плюс требует лишних данных. В общем, это классическая проблема: либо мы патчим код при загрузке и тратим память на copy-on-write, либо мы тормозим в рантайме. Память сейчас дешевле мегагерцев, вывод очевиден.
>>254266
> Тогда чем COM, например, не перемещаемый?
Пропустил. COM максимально перемещаемый по своей сути, но лишь потому, что целиком влезает в сегмент, и ты можешь выбрать ему любой сегмент. А вот в MZ EXE уже несколько сегментов, и нужны поправки для ссылок на эти сегменты. В PE EXE сегменты кончились, поэтому пришлось сделать поправки для вообще всех ссылок на данные.
>>254529
> Получается что сегментые регистры не меняются
Ну как бы да, основные дескрипторы стандартные, спокойно лежат себе в GDT одни на всех.
Сегменты - это тяжкое наследие x86. В других архитектурах оно если и есть, то в рудиментарном состоянии (например, в виде MPU, когда MMU нет). В x86-64 у тебя сегменты все равно под капотом остались, базы-лимиты игнорируются, а fs/gs вполне используются софтом. Смотри (cc -c -std=c11 -O0 file.c && objdump -d file.o):
int main(void) {
static _Thread_local int foo = 1;
return foo;
}
> Какая деятельность привела к тому, что изучили это?
Наличие трех- четырех-пятитомника от интела (подарили в бумаге, правда достаточно старые), ковыряние малвари, попытки в собственные ОС.
Кем работаешь если не секрет?
Есть годные доки/гайдлайны чтобы вкатиться в дровописание под прыщи? Там как иоктлы писать, как файловый доступ? Хочу вкатиться в pcie-махарайки на FPGA (блокчейн, машинлеарнинг вотэтовот всё).
OsDev советует Bochs для работ, связанных с разработкой операционных систем.
Как минимум компоновщик. Возможно к этому тебе нужно будет написать и ассемблер, не уверен. Препроцессор и компилятор берешь готовый. Поправьте меня, если я ошибся, самому интересно.
Бывает такое, это нормально, когда встречаешься с какой-нибудь новой концепцией. Лучше не читать один учебник пять раз, а посмотреть пять учебников, хоть где-нибудь да объяснено нормально.
Ты сейчас на этапе накопления первичных знаний. Спустя некоторое время копания в теме, понятия и термины выстроятся в твоей голове в более-менее упорядоченную схему, и станет намного легче. Главное не бросать, а стараться рассмотреть предмет интереса с разных сторон.
Линкер, как предлагает >>256118, либо лоадер ELF или PE вместо него. Лучше второе - быстрее, проще, удобнее из-за наличия готовых инструментов. И еще понадобится реализация сишной и/или крестовой стандартной библиотеки (точнее, стоит взять готовую и добавить поддержку твоих системных вызовов или апи).
Проиграл с большой мощностью.
Чексумму BIOS, само собой, подправить.
> опрашивает все устройства на матплате
Это зависит от того, что ты понимаешь под словом "все". Некоторые устройства можно обнаружить динамически, для некоторых можно постучаться в какой-то well-known IO-порт и узнать, есть ли там что-то, для каких-то устройств нужно заранее знать, есть ли оно. Читай спеку PCIe. Если шина позволяет так делать, то проблем или не будет, или будут минимальные.
>теоретически, можно каким-то раком припаять к матплате ещё один PCIe-порт и BIOS его обнаружит
Если чипсет(?) (квадратный чип на плате) поддерживает ещё один, то да.
Однако, в сегменте текста мы можем написать интерпретатор, который будет читать сегмент данных байт за байтом. А в сегменте данных мы можем разместить своеобразный код, который будет указывать интерпретатору, что ему следует делать.
Я правильно понимаю, что именно так и работают виртуальные машины?
> Я правильно понимаю, что именно так и работают виртуальные машины?
Какие-то так, как ты описал: гигантский свитч в сегменте кода и команды с данными в сегменте данных. Другие виртуальные машины JIT-ом компилируют свой байткод в машинный код. Третьи, которые которые эмулируют тот же x86 на x86 (например, VirtualBox или DOSBox), небольшими кусочками инструментируют машинный код, т.е., исправляют всякие переходы, работу с памятью и прочие "опасные" инструкции таким образом, чтобы код работал с виртуальным окружением. Т.е., вот выполняют вот эту самую динамическую рекомпиляцию:
> Таким образом, в защищённом режиме невозможна динамическая рекомпиляция программ.
Из того, что в сегмент кода нельзя писать, никак не следует, что ты в принципе не можешь записать в память машинный код. Фактически в современных ОС у сегмента кода (чей селектор лежит в cs) и сегмента данных (селектор в ds и прочих) база и лимит полностью совпадают. Процессор при чтении кода использует cs, инструкции, которые работают с памятью, по умолчанию используют ds/es (иногда ss), никаких проблем. Поэтому ты, конечно же, не можешь сделать mov dword[cs:addr],1 но никто не запретит тебе сделать mov dword[ds:addr],0xccfeeb90 и jmp addr. И даже если у тебя кастомная ОС, которая почему-то решила использовать похороненную интелом сегментацию, этой ОС все равно нужно как-то загружать программы в память, поэтому у нее будет (возможно временный) дескриптор сегмента, перекрывающийся с сегментом кода программы, и ОС скорее всего предоставит тебе API для его использования.
Если ты говоришь не о сегментации в x86(-64), а о сегментах программы (того же ELF) и куче (т.е., нельзя писать в .text, можно в .data), там защита использует атрибуты страниц (а не сегментов), и опять же никто тебе не мешает выделить страницу для данных (rw), написать туда, а потом пометить ее как код (rx). Чаще всего ты даже можешь сразу выделить страницу кода, в которую можно писать (rwx), но ОС и антивирусы такое не любят. Еще можно замапить одну и ту же страницу физической памяти с разными атрибутами.
Алсо, x86 сам решает за тебя большинство вопросов с кэшами, а вот на каком-нибудь ARM при записи исполняемого кода о сбросе кэша нужно помнить, иначе есть шанс спецэффектов.
> Я правильно понимаю, что именно так и работают виртуальные машины?
Какие-то так, как ты описал: гигантский свитч в сегменте кода и команды с данными в сегменте данных. Другие виртуальные машины JIT-ом компилируют свой байткод в машинный код. Третьи, которые которые эмулируют тот же x86 на x86 (например, VirtualBox или DOSBox), небольшими кусочками инструментируют машинный код, т.е., исправляют всякие переходы, работу с памятью и прочие "опасные" инструкции таким образом, чтобы код работал с виртуальным окружением. Т.е., вот выполняют вот эту самую динамическую рекомпиляцию:
> Таким образом, в защищённом режиме невозможна динамическая рекомпиляция программ.
Из того, что в сегмент кода нельзя писать, никак не следует, что ты в принципе не можешь записать в память машинный код. Фактически в современных ОС у сегмента кода (чей селектор лежит в cs) и сегмента данных (селектор в ds и прочих) база и лимит полностью совпадают. Процессор при чтении кода использует cs, инструкции, которые работают с памятью, по умолчанию используют ds/es (иногда ss), никаких проблем. Поэтому ты, конечно же, не можешь сделать mov dword[cs:addr],1 но никто не запретит тебе сделать mov dword[ds:addr],0xccfeeb90 и jmp addr. И даже если у тебя кастомная ОС, которая почему-то решила использовать похороненную интелом сегментацию, этой ОС все равно нужно как-то загружать программы в память, поэтому у нее будет (возможно временный) дескриптор сегмента, перекрывающийся с сегментом кода программы, и ОС скорее всего предоставит тебе API для его использования.
Если ты говоришь не о сегментации в x86(-64), а о сегментах программы (того же ELF) и куче (т.е., нельзя писать в .text, можно в .data), там защита использует атрибуты страниц (а не сегментов), и опять же никто тебе не мешает выделить страницу для данных (rw), написать туда, а потом пометить ее как код (rx). Чаще всего ты даже можешь сразу выделить страницу кода, в которую можно писать (rwx), но ОС и антивирусы такое не любят. Еще можно замапить одну и ту же страницу физической памяти с разными атрибутами.
Алсо, x86 сам решает за тебя большинство вопросов с кэшами, а вот на каком-нибудь ARM при записи исполняемого кода о сбросе кэша нужно помнить, иначе есть шанс спецэффектов.
Круто, пояснил как б-женька. Спасибо.
> как в бинарнике отличается значение от номера регистра
Положением, опкодом, признаком формы адресации. Виртуальную машину чего ты пишешь? Что-то свое? Если x86, тогда качай Intel SDM и читай том 2, глава 2 "Instruction Format".
Для каждого байта операции определяй положение регистра и данных строго. Я таг собираюсь делать.
Поясните за многопоточность.
Есть: одноядерный процессор, два потока
Вопрос:
Если процессор одноядерный то два потока ни в каком случае не могут исполняться одновременно? Будет просто даваться квант времени одному потоку, квант другому?
До вчерашнего дня я думал именно так, но,
с толку сбивает вот что:
В википедия аппаратная реализация многопоточности делится на 2 варианта:
а) Временная (то что я описал выше)
б) Одновременная
Simultaneous multithreading (SMT) is a technique for improving the overall efficiency of superscalar CPUs with hardware multithreading. SMT permits multiple independent threads of execution to better utilize the resources provided by modern processor architectures.
Проясните пожалуйста этот момент.
Есть варианты, когда на одном физическом ядре дублируют пару исполнительных блоков и делают настройку, чтобы он прикидывался двумя ядрами, типа Hyper Treading. Но это чётко видно, процессор представляется ОС как двухядерный. Так что да, на одноядерном процессоре без HT или аналога два потока не смогут исполняться одновременно.
>Но это чётко видно, процессор представляется ОС как двухядерный
Воот, вот этого не хватало. Спасибо большое
>типа Hyper Treading
Жаль, что прирост производительности это даёт редко (а в моём случае даже наоборот получается).
Я имею в виду время выполнения.
Во-первых, большая O() - это метрика роста, а не скорости. Во-вторых, нет. Процессор читает из памяти блоками, блоки кэшируются, соответственно, следующий доступ к адресу, попавшему в кэшлайн, будет гораздо дешевле. Ниже уровнем там тоже не все равномерно - зависит и от типа памяти, и от загруженности шины.
>O() - это метрика роста
Об этом и спрашиваю. По модулю кэширования и виртуализации время обращения зависит от адреса?
Кстати, можно напрямую контролировать кэширование и доступность страниц виртуальной памяти? Это, вообще, сделано прозрачно для программиста?
> Кстати, можно напрямую контролировать кэширование
Да, можно отключать, задавать способ кэширования какого-то региона, можно чистить кэш итд.
> Кто-нибудь fasmg уже использует?
Я использую, но не вижу смысла им собирать x86-64 - он в разы медленнее, а все вкусные фичи уже бэкпортированы в fasm1. Вот кастомные ассемблеры и прочие генераторы бинарников я на нем уже пару лет пишу, мне норм.
> Но ведь будущее за fasmg
У фасма вообще нет будущего, пока он написан на себе самом. У нас ARM в разы больше, чем x86-64, а фасм ведь даже не x86-64, он 32-битный. Если его не перепишут на Си или под кастомную вм какую-нибудь, он рано или поздно умрет. Вариант с вм, кстати, предлагали еще во время обсуждения кроссплатформенных плагинов к IDE на фасмконе в середине 2000х, а воз и ныне там.
Это конечно важные технические обстоятельства. Но, ведь, преимущество fasmg - это беспрецедентно мощные макросы макросы повсюду. В этом он превосходит всех, я понимаю.
> это беспрецедентно мощные макросы
...для понимания поведения которых нужно детально знать, как устроен фасм. И даже тогда обнаруживать, что что-то не работает или работает не так, как ожидалось. Если тебе нужны именно макросы, ты можешь взять python, keystone, и дальше твои fp.write(insn_bytes) не ограничены абсолютно ничем, в отличие от фасма, где ты просто физически не можешь делать всякие странные вещи типа struct с 50к элементами из-за особенностей самого фасма и того, что struct - это макрос.
> В этом он превосходит всех
Собственно, из уникальных вещей в фасме только многопроходная оптимизация по размер/разрешение имен и расширенные возможножности манипуляции с данными, особенно блок virtual. Остальное есть и/или реализуемо с привлечением внешнего препроцессора в других ассемблерах.
Есть древняя библиотека (в папке msvcrt версии 5.00.7128 ну и дата разработки 1998 г), содержащая API (несколько десятков методов). Документации и инклюд/тлб-файлов и ничего такого нет, в интернете сведений почти нет. Все, что удалось вытянуть - это названия экспортируемых функций.
Есть программа, которая эту SDK использует.
1) Реально ли зареверсить библиотеку и получить инфу о прототипах функций, порядке вызова и т.д? Естественно, конечная цель - заюзать либу в своем коде.
2) Если да, то с чего начинать?
> Как исследовать Win32 DLL-ку?
Frida, чтобы логировать вызовы апи, можно методом внимательного просмотра лога восстановить прототипы, смысл параметров и т.д. IDA±HexRays, чтобы посмотреть (псевдо)код и восстановить утраченное знание. На посиделки в IDA придется потратить некоторое время, никакой магии она не делает.
> Реально ли
Более чем.
Можешь либу выложить тут, вряд ли там что-то секретное или коммерчески применимое от 98 года-то.
>Можешь либу выложить тут, вряд ли там что-то секретное или коммерчески применимое от 98 года-то.
http://rgho.st/private/7sNLM7DbJ/1c00a4e4d5f38525e1234a5a2b8c5d2e
Эта либа-синтезатор речи.
Запускаем файл, он устанавливается (только под админом плюс на x64 бывают проблемы и надо руками в реестр прописывать, на x32 вроде работает даже на новых версиях винды до десятки включительно). Распаковывается в %WINDIR%\lhsp\.
LHSTTS60.exe - программа, которая использует библиотеку. Чтобы она заговорила, надо нажать file -> open, выбрать какой-нибудь txt-файл и потом нажать кнопку Play, либо в главном окне нажать About (прога проговаривает информацию из окна о программе).
В принципе она вроде бы даже работает без установки, если просто все извлечь.
Там много всякого (подключаемые модули с разными языками и голосами), но экспорт по ходу идет из TTSMGR60.DLL, а остальные файлы - это уже внутренние зависимости.
> Эта либа-синтезатор речи
Если цель - лишь заставить это говорить, то TrueVoice умеет работать через COM (MS Speech API), это строк двадцать на Си плюс обработка ошибок, при этом ты можешь использовать и другие синтезаторы, которые умеют в Speech API, не изменив ни строчки кода. Это тебя почему-то не устраивает? Не хочешь таскать с собой дистр Speech API? Какие-то дополнительные фичи нужны? В принципе, если хочешь, оставь какие-нибудь контакты (не телеграм) - я могу поучаствовать.
>>273640
Вроде было fas2pdb (гуглится), и тут посмотри еще https://board.flatassembler.net/topic.php?t=9792
https://board.flatassembler.net/topic.php?t=20753
Этот плагин у меня не работает (коллапсится весь дебаггер без предупреждения).
Поясните, в чём ошибка. В s у меня находится слово, я беру страший байт этого слова и пытаюсь перенести его в 8-разрядный регистр AH. Байт же должен поместится в 8 разрядов, что ему не нравится?
Что за синтаксис? Разве там не должно быть mov ah , ds:[s + 1] ? Если s - метка или препроцессорная переменная здесь читай адрес
>Что за синтаксис?
Turbo Assembler
>Разве там не должно быть mov ah , ds:[s + 1] ?
Попробывал, это ничего не меняет.
>Если s - метка или препроцессорная переменная здесь читай адрес
s - слово в сегменте данных (s dw 88ffh). То есть мне надо не ds:s+1 писать, а, например, ds:[6], я правильно понял?
Теперь вроде работает, но странное дело: дальше я пересылаю третий символ из строки symbols прошлым способом, но на это он ошибок не выдаёт. Как же так?
Метка symbols как объявлена?
Если symbols db "..." , то и нарезать данные ассемблер будет побайтово.
Да, db, тогда всё понятно. Но у меня есть ещё один глупый вопрос: я же заношу все эти hex-коды в память, почему отладчик мне сообщает, что там хранятся не мои коды, а какой-то мусор?
Сразу так не скажешь.
По тем ли адресам ты дамп просматриваешь?
Может, твоя программа уже поменяла эту память.
Ну, наверное по тем, если по листингу транстляции судить. Да и где мне их ещё искать, там же от 0000 до FFFF очень много всего. Не знаю, могла ли программа изменить эту память, я ведь её ещё даже не запускал.
Как ты отлаживал, не запустив? Не понимаю.
Запускаешь отладку. Останавливаешь (брейкпоинтом?). Ищешь нужные адреса в дампе. Или ищешь в дампе по значению.
Открываю отладчик, вижу что в ds совсем не те цифры, которые я задавал, ну и ладно. Запускаю в пошаговом режиме. Terminated, exit code 0. В ds так ничего и не изменилось. Что я делаю не так?
Там же должно быть сразу, ещё перед запуском
ds:0000 9A 8B 7C 6D 5E 88 FF 40
ds:0008 23 24 00 00 00 00 00 00
Разве нет? Что он тогда пересылать-то будет?
Да, действительно, спасибо. Но, честно говоря странно, у меня же не .com, а .exe.
> Но, честно говоря странно, у меня же не .com, а .exe
А, ну так ты смотришь по DS, судя по скриншоту. При старте DS = сегменту PSP. Смотри по CS.
>Там же должно быть сразу, ещё перед запуском
Зависит от отладчика. До запуска в дампе может находиться страница процесса самого отладчика, а не твоей программы.
Аноны, можете рассказать что делает регистр swr в x86 FPU? Ну или хотя бы ткнуть носом туда, где подробно написано про то, как работает стек FPU под капотом.
Эээ, Simply FPU, первая глава, более чем подробно. Вроде как где-то даже был перевод на русский.
> как работает стек FPU под капотом
Там же классический стек. В status word в трех битах лежит индекс "текущего" физического регистра top (0...7), который является верхушкой стека (st0). Относительно него (по модулю 8) адресуются логические st0-st7 (т.е., st7 - это физический регистр с номером (top + 7) % 8 или, так как мы байтоебы, (top + 7) & 7). Изначально (и после finit) в top 0, стек растет вниз. Т.е., когда ты делаешь какой-нибудь push - например, fld1, сопроцессор декрементирует индекс (top = (top - 1) & 7), и затем пишет в свежий st0 данные: x87_regs[top] = 1.0. Когда ты делаешь pop - например, fstp [mem], сопроцессор читает данные из st0, т.е., x87_regs[top], а потом инкрементирует индекс (top = (top + 1) & 7).
Сильно не заморачивайся, это мертвая технология, сейчас все под SSE собирается, даже если особой выгоды от SIMD нет. Разве что чей-то старый код реверсить - тогда да, нужно.
> The freeware version of IDA v7.0 has the following limitations: > lacks support for many processors, file formats, debugging etc...
Аноны, в IDA отредактировал инструкцию, но при запуске дебага ничего не меняется, что не так?
Тебе должно было сказать:
> The database has been patched. There might be some inconsistency between the disassembly in the database and the actual debugger process.
Для отладки используется API винды, винда отлаживаемую программу из образа грузит, где патчей нет. Почему IDA не патчит память уже после загрузки образа - хуй знает, вон Олька патчи применяет из прошлых сессий, и ей вполне норм. Ну и поэтому все, что есть в меню Edit->Patch program предназначено в основном для Edit->Patch program->Apply patches to input file. Если применишь к образу, то безусловно работать будет.
Хотел тебе предложить самому наговнокодить полторы строки на питоне, но внезапно оказалось, что на момент получения dbg_process_start у idaapi.visit_patched_bytes висит только хуй, а про патчи оно на время отладки забывает. Но... в общем, вот тебе по-быстрому сделанный на коленке костыль: https://hastebin.com/kozazidoxe.py (положить в <IDA>\plugins и не забыть удалить, когда отпадет необходимость, потому что кривое говно). Можешь сам допилить детект типа процессора, чтобы оно не торчало в памяти для какого-нибудь Z80 и самое главное - обработку rebase. В текущем виде плагин работает только когда адрес образа в иде равен адресу образа в памяти при отладке, но при отладке длл, эта длл может быть перемещена, и тогда плагин пропатчит не свой образ. Там нужно ловить segm_moved в IDBHook и исправлять адреса патчей, которые в этот сегмент попадают, ничего сложного.
Ну и как обычно, не мог не наебаться: https://hastebin.com/yutitufela.py (удаляет патчи, когда исправляешь обратно на оригинал).
Спасибо анон, буду пробовать.
> НО КАК БЛЯТЬ ПАТЧИТЬ-ТО
Ну так если ты ручками пройти можешь, исправь нужные джампы или чтения флагов. Тыкаешь в x64dbg пробел, правишь код, тыкаешь View->Patch file, тыкаешь Patch, схороняешь, готово.
> ПИСАТЬ КЕЙГЕН
Разбираешь алгоритм, пишешь. Или выдираешь чек и брутфорсишь нахуй.
В чем вопрос-то? Не знаешь асма? Учи. Не понимаешь, что происходит? Тыкай ; на каждой строчке и комментируй, что (и главное зачем!) делает инструкция. Возможно, имеет смысл посмотреть флоу по сноуманом по F5, но если уж дело дошло до такого, возьми лучше IDA/HexRays, сноуман говно редкостное. Собирай свои крякми уровня if (!strcmp(key, "magic")) puts("Success"), смотри, что за код генерится и пробуй запатчить его.
Алсо, можешь сюда притащить что-нибудь, разберем с анонами.
Асм не учил, знаю немного c/c++ и винапи. IDA/hexrays это платные тулзы на сколько я помню. x64dbg + HxD + exeinfope + cff explorer - такого набора не хватит?
> IDA/hexrays это платные тулзы на сколько я помню
Среди бесплатных ты аналогов не найдешь даже близко. Но на первое время одного лишь x64dbg хватит.
Так купи треснутую Иду.
>тред нелегальной йобы под названием реверс-инжиниринг
>покупать софт не потому что это удобно и нужна поддержка, а потому что воровать не хорошо
> тред нелегальной йобы под названием реверс-инжиниринг
В России можно реверсить софт, даже если лицензия запрещает, если тебе это нужно, чтобы с этим софтом работать. Нельзя результаты выкладывать.
А что, не в России прямо смогут узнать, что ты реверсишь у себя дома в тёмном-тёмном УБЕЖИЩЕ ХАКЕРА в подвале?
Есть вот такой известный подход. В светлых-светлых офисах, за зеленые-зеленые бумажки. https://en.wikipedia.org/wiki/Chinese_wall#Reverse_engineering
Ну да, я неправильно выразился. Можно реверсить для обеспечения взаимодействия со своей прогой, можно реверсить вирусы экспертам по безопасности. Но что-то я сомневаюсь, что человек учится на крэкми для этих целей, а не чтобы научиться пиздить софт
Реверсят софт для того, чтобы понять/посмотреть как там чо работает и получить с этого профиты. Я же хочу вкатиться в реверс для анализа малвари да мамин этичный хакер итт. Сейчас половина софта фри, другая часть с бесконечными триалками и лишь специализированный софт хуй просто так получишь. Ту же ИДу например, VM workstation итд хотя кого я обманываю, все мы знаем где лежат кряки.
> его можно в исполняемый файл сконпелировать
Чтобы получить более-менее нормальный код, нужно долго и усердно расставлять типы. И все равно не факт, что оно будет работать - не весь код декомпилируется корректно (иногда это можно исправить, иногда проблемы в самом HexRays). Например, из-за ошибок типизации HexRays может выкинуть половину функции, причем как раз ту, что делала полезную работу. Так что результат декомпиляции все равно приходится перепроверять, доводить руками, плюс есть всякие __usercall/__spoils и JUMPOUT, которые компилятору не объяснишь. Ну и когда дело доходит до крестов, все становится сильно хуже.
О, нихуя себе, и такое есть
Чо? Нет. Никаких единиц количества данных, откуда ты взял-то это вообще? Есть два вида многозадачности: кооперативная и вытесняющая. В кооперативной поток сам выбирает, когда ему поделиться процессором, он может не делиться вообще - тогда будет примерно так, как ты описываешь, но пользователи будут ругать автора программы плохими словами. В вытесняющей многозадачности есть какой-нибудь таймер, и процессор выполняет в потоке столько инструкций, сколько успеет между двумя тиками таймера, а после этого управление может быть отдано еще кому-нибудь (а может и не быть).
> процессы могут прерываться и могут создавать новые потоки
Процесс сам по себе кода не выполняет, его выполняют потоки. Процесс - это некая сущность, хранящая информацию об одном или нескольких потоках и их общей памяти (и о других общих для этих потоков ресурсах, например, о дескрипторах файлов).
Из машинного кода в ассемблер - дизассемблер. В язык высокого уровня - декомпилятор.
> Из машинного кода в ассемблер - дизассемблер. В язык высокого уровня - декомпилятор.
Но это ж ущербные решения, в том смысле, что дизассемблированный код обратно в бинарник не сконпелируется. Про декомпиляторы чуть выше говорили, что тоже функции могут побиться. Или я что-то недопонимаю?
> дизассемблированный код обратно в бинарник не сконпелируется
Скомпилируется, если ничего не упустить. Основная проблема - отличить офсеты от констант.
> Про декомпиляторы чуть выше говорили, что тоже функции могут побиться
Это если полагаться лишь на тупую железку, пытаясь сразу, без доработок, засунуть выхлоп хексрейсов в компилятор.
> Фарш невозможно провернуть назад
Это действительно невозможно, но приложив некоторые усилия, из него можно собрать нечто похожее на корову. Не ту, которую провернули, но очень похожую. Правда, иногда это даже дольше, чем вырастить новую корову.
С дизассемблированным кодом проблем быть не должно.
Декомпиляторы да. В моей молодости их вообще не существовало нормальных.
> С дизассемблированным кодом проблем быть не должно.
Т.е бинарник можно открыть в ida pro, потом по f10 вроде получить ассемблерный код, и потом его просто засунуть в компилятор, и скомпилированное будет работать?
ida pro даже без хексрейса это не совсем голый декомпилятор. Посмотри в сторону дизассемблеров попроще, которые берут машинный код и 1-в-1 переводят.
Сначала View->Problems как минимум, но и они не дают 100% гарантии.
> Посмотри в сторону дизассемблеров попроще, которые берут машинный код и 1-в-1 переводят.
Например?
Не знаю, какие именно дизассемблеры имел в виду анон выше, но я знаю самый простой:
db 0b8h,00h,4ch,0cdh,21h
Такой дизасм точно скомпилируется!
> db 0b8h,00h,4ch,0cdh,21h
> Такой дизасм точно скомпилируется!
Всякие хелловорлды из 3,5 байт понятно что скомпилируются. Речь всё-таки о более жизненных примерах, н-р нормальные среднестатистические бинарники.
Это я пошутить пытался, но, видимо, безуспешно.
Еще раз, скомпилируется все, что угодно, если ассемблер поддерживает тот синтаксис, что генерирует дизасм (всякие assume, offset и ptr). А вот работать собранный код будет при соблюдении любого из условий:
1) Дизасм не исправлялся, и ассемблер не занимается самодеятельностью (вроде замены jmp near на jmp short, lea на mov и т. д.), и линкер не занимается самодеятельностью, переставляя или объединяя секции, т. е. в скомпилированном коде адреса инструкций и данных в коде никуда не уезжают относительно оригинала.
2) Вы вместе с дизасмом прошли по всем (абсолютно всем!) числам в коде и заменили все числа, которые являются адресами на метки (и/или арифметику с метками). Т. е., чтобы в случае, если эти адреса изменятся (см. пункт 1), ассемблер мог правильно их пересчитать. Как бы ни старалась IDA, она в этой задаче лажала и будет лажать, потому что такое не всегда возможно решить даже человеку. Например, нельзя ничего сказать про dd 0401000h, пока не найдешь код, который к нему обращается; не всегда можно понять, занимается ли lea edx,[eax+4000h] целочисленной арифметикой или вычислением адреса и т. д.
Так как первый вариант по сути бесполезен, а даже единственная ошибка определения адреса во втором варианте закладывает в исходник мину замедленного действия, проще всего выбрать третий вариант и патчить бинарники, не пересобирая их. Хотя я знаю как минимум три случая, когда большие исполняемые файлы (больше полуметра, а один еще и на крестах с MFC при этом) были дизассемблированы, пересобраны и даже вроде бы работали. Впрочем, не факт, что они работали всегда и правильно.
>Например, нельзя ничего сказать про dd 0401000h
Как же процессор что-то говорит про dd 0401000h?
Процессор знает только про текущую инструкцию и все. Еще он пытается декодировать несколько инструкций вперед, иногда у него это даже получается, но это отнюдь не означает, что то, что он декодировал - инструкции, и что они будут выполнены:
push 0
call _exit
inc ecx
inc edx
inc esp ; На самом деле три inc - это db 'BAD', и оно не выполнится.
Если к foo dd 0401000h будет обращаться инструкция типа call [foo], то это однозначно адрес (если, конечно, инструкция call - на самом деле инструкция, а не похожий набор байт). Если будет mov eax,[foo], это еще не гарантирует, что внутри не адрес. Дальше может быть jmp eax, а может и не быть. А может быть работа с этим двордом физически отсутствует в данном модуле, и что-то решить вообще невозможно. Пример:
; Функция из exe, вызывает точку входа плагина и передает ему параметром указатель на структуру с API-функциями приложения. Ну вот решил автор, что ему так удобнее, чем через экспорты в exe.
init_plugin:
mov ecx,plugin_entry ; Как-то получен через LoadLibrary.
push api_ptrs
call ecx ; plugin_entry
retn
; Возможно, указатели на какие-то функции. Допустим даже, что по этим адресам на самом деле есть функции.
api_ptrs:
dd 401000h ; А вот хуй, это версия приложения 64.16.00
dd 411103h ; А вот это и правда указатель на функцию.
db "FOO",0 ; А вот хуй, это ида слажала, там dd 004f4f46h и это указатель на функцию.
И вот поди и разбери. Это, конечно, крайне надуманный пример, но этот код в принципе не декомпилируется со 100% уверенностью. Ни человеком, ни машиной. Обычно решается сравнением разных версий приложения в надежде что то, что адреса - изменилось, а то, что константы - нет, но иногда другой версии просто нет.
cmp al,57d
jbe digit_compare
jmp letter_compare
digit_compare:
cmp al,48d
jle output_asci
jmp letter_compare
Что делать с переходами?
cmp al,57
ja letter_compare
cmp al,48
jb letter_comare
что_то_делаем_с_цифрой:
...
jmp куда_то
letter_compare:
...
jmp куда_то
Действительно, я хуево посчитал.
>Посмотри в сторону дизассемблеров попроще, которые берут машинный код и 1-в-1 переводят.
А конкретно? Что из этого https://en.wikibooks.org/wiki/X86_Disassembly/Disassemblers_and_Decompilers лучше?
Да, я ошибся с переходами. В моем случае были нужны jae и jbe т.к. я проверяю код введенного символа на соответствие ascii коду цифры.
Нужно что-то, с помощью чего можно с высокой степенью вероятности получить из бинарников компилирующийся во что-то работоспособное ассемблерный код.
Бля, ты не решение, ты ЗАДАЧУ озвучь. Зачем тебе это?
Написать программу на языке ассемблера, которая обрабатывает нажатия клавиш на клавиатуре и выдаёт на экран следующую информацию:
1) ASCII-код символа, если была нажата алфавитно-цифровая клавиша основной клавиатуры.
2) Строку «Расширенный код», если была нажата функциональ-ная клавиша, клавиши дополнительной клавиатуры или комбинации клавиш с «ALT» и «CTRL».
Программа должна предварительно чистить буфер клавиатуры. Информация о каждом нажатии должна выводиться в новой строке (предыдущие сведения не затираются). Символы должны вводиться без эха. Программа должна завершиться по нажатию клавиши «ESC».
Я осуществил первый пункт задачи, но не могу понять как одновременно с определением нажатия алфавитно-цифровых клавиш определять нажатие функциональных клавиш. Правильно ли я понимаю, что если скан-код не соответствует алфавитно-цифровой клавише, то надо проверять буфер
клавиатуры и вызывать прерывание обработки функциональных клавиш?
Ну ведь есть int 16h/ah=10h, она выдает тебе всю нужную информацию. Состояние Ctrl/Alt по int 16h/ah=12h.
Можно прямо из 0000h:041Eh читать.
>Посоветуйте, что/где почитать про параллелизм для x86-64 под Win? Именно хардкорный параллелизм, а не какое-нибудь concurrency или multithreading/multitasking. CAS, транзактные/атомарнае операции, ну и так далее.
https://www.threadingbuildingblocks.org/
Что за спецуха и ВУЗ, если не секрет?
можно ли изменить директиву описания данных? тобиш
вот
a dw 0
можно ли сунуть чо-нить туда
mov a,[ax]
все разобрался, a+bx+di получается
Прикладная информатика, ОГУ им. Тургенева.
>>283240
Тут такие вопросы возникли. Как 'управлять' многопроцессорной/многоядерной системой в Win32? Вот, наприер, если есть участок кода X, и я хочу потребовать, чтобы этот участок выполнялся гарантированно на разных ядрах, либо вообще не выполнялся. Не важно на каких (пусть ОС решает), главное, чтоб на разных. Как этого добиться? Как сделать, чтобы X выполнялся одновременно тремя (ровно) ядрами? Как добиться каких-то гарантий одновременности? Чтобы не получить это как результат переключений в рамках вытесняющей многозадачности. Это может быть сделано прозачно, вообще? Или, например, когда ядро 1 выполняет участок X, может ли оно узнать, выполняется ли X каким-то другим ядром сейчас?
> я хочу потребовать, чтобы этот участок выполнялся гарантированно на разных ядрах
SetThreadAffinityMask.
> Как сделать, чтобы X выполнялся одновременно тремя (ровно) ядрами?
Напиши свою ОС/возьми ртос, и после долгой ебли со сбросом кэшей у тебя все равно не будет 100% гарантии.
> Это может быть сделано прозачно, вообще?
Нахуй никому не нужно. Максимум, что нужно для реальных практических задач - возможность узнать, сколько всего ядер (чтобы узнать, сколько потоков порождать) и возможность раскидать потоки по ядрам. Такое есть везде.
> Или, например, когда ядро 1 выполняет участок X, может ли оно узнать, выполняется ли X каким-то другим ядром сейчас?
Да, заведи себе атомарную переменную и инкрементируй ее при входе в блок кода, декрементируй при выходе. Банальные InterlockedIncrement/Decrement вполне подойдут.
Ну и главный вопрос: НАХУЯ?
>SetThreadAffinityMask
Недостаточно гибко. Надо не на конкретных, а на разных, по модулю планировки планировщиком ОС.
>Да, заведи себе атомарную переменную и инкрементируй ее при входе в блок кода, декрементируй при выходе
А где гарантии одновременности.
>НАХУЯ?
ТАКНАДА Для полноценного параллелизма, полагаю.
>Нахуй никому не нужно.
Печально.
> Для полноценного параллелизма, полагаю.
Ты точно с онанизмом не путаешь? - Эй, сосед, ты тоже сейчас на это дрочишь? - Да! Как здорово дрочить вместе!
Я просто не понимаю, почему ты считаешь, что вот если все дрочат одновременно на один пик - это полноценный параллелизм, а если кончают не на друг друга вместе - это уже неполноценный. Мне вот рассказывали, что нужно наоборот изобретать всякие lock-free алгоритмы, чтобы не отвлекаться на соседей.
>Мне вот рассказывали, что нужно наоборот изобретать всякие lock-free алгоритмы, чтобы не отвлекаться на соседей.
Забудьте всё, чему вас учили. Тебе впарили concurrency под видом параллелизма.
Чет проиграл c этого челенджа. RunPE 1% смогли только вскрыть? анпакается + дампится за 10 секунд же, втф
Жму Trace > кудаа сохранить лог, а на выходе лог пустой (это в x64dbg)
в ольке же все ок.
Пишут жи, что надо сначала формат задать. {p:cip} {i:cip}
Судя по количеству эльфов, это линуксореверсеры, им винду нечем, а отлаживаться олькой под вайном - это очень веселое развлечение, я пробовал.
Зачем отлаживать?
Я большинство статическим анализом и z3 вскрыл (ну нету у меня linux64, android и прочего)
Скинь минимальный пример. Скорее всего, ты неправильно определяешь extrn импортов или неправильно их вызываешь. Например, ты делаешь call [ExitProcess], и у тебя ExitProcess - не __imp__ExitProcess@4 (символ с префиксом __imp__ по соглашению ссылается на IAT), а thunk, т.е., _ExitProcess@4: jmp [__imp__ExitProcess@4], т.е., ты читаешь код как адрес, и оно падает. Или ты наоборот делаешь call ExitProcess, а ExitProcess - у тебя не thunk, а элемент IAT, и, конечно, выполнение адреса как кода тоже ни к чему хорошему не приводит.
Чтобы узнать импортируемые из kernel32.lib символы, я смотрю в kernel32.def сгенерированый polib /makedef для c:\Program Files (x86)\Windows Kits\10\Lib\10.0.17763.0\um\x64\kernel32.lib
и вижу, например, "GetModuleHandleA" ; KERNEL32.dll
и поэтому в .asm файле объявляю внешние символы, например, так:
extrn 'GetModuleHandleA' as GetModuleHandleA:qword
Далее в .asm файле вызываю invoke GetModuleHandleA , 0
Как, тогда, узнать какие символы импортируются из .lib? Какие мне надо использовать, для вызова процедур из .dll?
> extrn 'GetModuleHandleA' as GetModuleHandleA:qword
Именно об этом я и говорил. Ты делаешь invoke proc, invoke делает fastcall [proc], fastcall делает call [proc], получается:
call [GetModuleHandleA]
при этом линкер генерирует из библиотеки импорта:
GetModuleHandleA: jmp qword[cs:__imp_GetModuleHandleA]
А надо:
extrn '__imp_GetModuleHandleA' as GetModuleHandleA:qword
(64-битный fastcall декорируется по-другому, поэтому нет второго подчеркивания после imp и собаки с цифрой в конце, как у меня >>284645 тут).
Или вызывай как fastcall GetModuleHandleA,0 вместо invoke, ничего больше не меняя, тогда fastcall будет делать call GetModuleHandleA, и все будет красиво (кроме лишнего джампа).
>>284649
> Как, тогда, узнать какие символы импортируются из .lib?
Экспортируются. Возьми 7-Zip, открой .lib-файл как архив, внутри будет 1.txt с нормальными именами (в 2.txt - отсортированные), можешь его куда-нибудь скопировать и там смотреть.
> Какие мне надо использовать
Для виндовых импортов стандартная форма сссылки на IAT: __imp_decorated_name, где первое подчеркивание... в общем, традиционное и присутствует всегда, _imp_ - индикатор импорта, decorated_name в 64-битной винде - просто имя апи. ExitProcess -> __imp_ExitProcess.
>Экспортируются
То есть, да.
Зачем в 2.txt два символа для GetModuleHandleA? Чем они отличаются?
522.KERNEL32.dll GetModuleHandleA
522.KERNEL32.dll __imp_GetModuleHandleA
Многие либы 7-zip открыть не может, например, user32.lib, gdi32.lib и другие.
> cannot open file
Хуй знает, у меня всегда работало. 7-Zip слишком старый? Ну dumpbin_или_podump /linkermember:1 filename.lib тогда.
> Зачем в 2.txt два символа для GetModuleHandleA?
Я это два поста подряд писал, ты читал их вообще?
В PE-файлах есть IAT (import address table) - это просто такой большой список адресов типа:
__imp_GetModuleHandleA dq ?
__imp_ExitProcess dq ?
...
и так для каждой импортированной функции (взгляд на уровне линкера). При загрузке винда в эти dq прописывает непосредственно адреса соответствующих функций. Ты можешь сделать call qword[__imp_ExitProcess], т.е., процессор прочитает из кворда __imp_ExitProcess адрес и сделает на него call.
Дальше. Во времена 95 винды, некоторые длл (user32/kernel32, например) были общими для всех процессов. В смысле, не как сейчас, copy-on-write у некоторых секций, а реально общая память - при патче длл в одном процессе память менялась для всех процессов. Это создавало неприятные проблемы при отладке: попытка поставить брейкпоинт на апи-функцию (т.е., заменить первый байт функции на int3) приводила бы к тому, что любой процесс, вызвавший эту функцию падал (потому как если отладчика у процесса не было, исключение от брейкпоинта обработать и восстановить замененный байт было некому). На самом деле, запись в общие длл была вообще запрещена если не использовать хаки вроде вызова VxD-сервиса _PageModifyPermissions, поэтому никто не писал и никто не падал по этой причине, лол, но брейпоинтов не было в любом случае. Чтобы обойти эту хуйню, придумали так называемые thunks, переходники. Компилятор вместо вызова апи функции напрямую, т.е., вместо вот этих call qword[__imp_GetModuleHandleA], генерил переходник (естественно, с поправкой на 32-битность):
GetModuleHandleA: call qword[__imp_GetModuleHandleA]
(имена, опять же, с точки зрения линкера). Это позволяло ставить брейкпоинты на переходники, а не на API, переходники были в самом образе, а не в системной длл, этот образ отладчик мог патчить как угодно, и поэтому вышеописанных проблем не возникало. Потом, когда пришло NT-ядро, в которой общие длл заменили нормальным copy-on-write, механизм все равно остался, потому что: 1) он позволял ставить брейкпоинты на API, вызванные именно твоим модулем, а не кем-то еще (это то, чего ты хочешь в 99% случаев); 2) он позволял уменьшить количество релоков (потому что call [iat_entry] требует абсолютного адреса iat_entry, т.е., в случае DLL - релока к каждому вызову API, а call thunk_entry относительный, и релок нужен только один - в самом thunk для абсолютного адреса в jmp [iat_entry]).
Поэтому у нас два вида символов. Если ты используешь __imp_Name, функция вызывается сразу через indirect call через IAT, если используешь просто Name, линкер генерирует переходник, и делается relative call на переходник, который делает indirect jump через IAT.
В четвертый раз описывать не буду, извини.
> cannot open file
Хуй знает, у меня всегда работало. 7-Zip слишком старый? Ну dumpbin_или_podump /linkermember:1 filename.lib тогда.
> Зачем в 2.txt два символа для GetModuleHandleA?
Я это два поста подряд писал, ты читал их вообще?
В PE-файлах есть IAT (import address table) - это просто такой большой список адресов типа:
__imp_GetModuleHandleA dq ?
__imp_ExitProcess dq ?
...
и так для каждой импортированной функции (взгляд на уровне линкера). При загрузке винда в эти dq прописывает непосредственно адреса соответствующих функций. Ты можешь сделать call qword[__imp_ExitProcess], т.е., процессор прочитает из кворда __imp_ExitProcess адрес и сделает на него call.
Дальше. Во времена 95 винды, некоторые длл (user32/kernel32, например) были общими для всех процессов. В смысле, не как сейчас, copy-on-write у некоторых секций, а реально общая память - при патче длл в одном процессе память менялась для всех процессов. Это создавало неприятные проблемы при отладке: попытка поставить брейкпоинт на апи-функцию (т.е., заменить первый байт функции на int3) приводила бы к тому, что любой процесс, вызвавший эту функцию падал (потому как если отладчика у процесса не было, исключение от брейкпоинта обработать и восстановить замененный байт было некому). На самом деле, запись в общие длл была вообще запрещена если не использовать хаки вроде вызова VxD-сервиса _PageModifyPermissions, поэтому никто не писал и никто не падал по этой причине, лол, но брейпоинтов не было в любом случае. Чтобы обойти эту хуйню, придумали так называемые thunks, переходники. Компилятор вместо вызова апи функции напрямую, т.е., вместо вот этих call qword[__imp_GetModuleHandleA], генерил переходник (естественно, с поправкой на 32-битность):
GetModuleHandleA: call qword[__imp_GetModuleHandleA]
(имена, опять же, с точки зрения линкера). Это позволяло ставить брейкпоинты на переходники, а не на API, переходники были в самом образе, а не в системной длл, этот образ отладчик мог патчить как угодно, и поэтому вышеописанных проблем не возникало. Потом, когда пришло NT-ядро, в которой общие длл заменили нормальным copy-on-write, механизм все равно остался, потому что: 1) он позволял ставить брейкпоинты на API, вызванные именно твоим модулем, а не кем-то еще (это то, чего ты хочешь в 99% случаев); 2) он позволял уменьшить количество релоков (потому что call [iat_entry] требует абсолютного адреса iat_entry, т.е., в случае DLL - релока к каждому вызову API, а call thunk_entry относительный, и релок нужен только один - в самом thunk для абсолютного адреса в jmp [iat_entry]).
Поэтому у нас два вида символов. Если ты используешь __imp_Name, функция вызывается сразу через indirect call через IAT, если используешь просто Name, линкер генерирует переходник, и делается relative call на переходник, который делает indirect jump через IAT.
В четвертый раз описывать не буду, извини.
А не можешь выложить user32.lib из десяточного SDK? Может они опять новый формат завезли, а я сижу и не знаю?
> GetModuleHandleA: call qword[__imp_GetModuleHandleA]
Имелось в виду
GetModuleHandleA: jmp qword[__imp_GetModuleHandleA]
надо было спать идти
>список всех адресов winapi
Нету. От обновления к обновлению, от версии системы и т.д. они меняются. А что уж говорить про ASLR?
Им дали GetProcAddress, а они по захардкоженым адресам ходют.
> Но откуда этот адрес? Как его узнать?
Гуглишь PEB_LDR_DATA, идешь по любому из xxxModuleList, парсишь PE, парсишь экспорты, получаешь адреса. А вообще, да, расскажи, чем тебя GetProcAddress не устраивает? Он делает все то же самое, но абсолютно бесплатно.
> хэши winapi
Нужны только в шелкодах, чтобы не хранить имена апи-функций в виде строк. Это просто хэши имен апи-функций, функцию хэширования можешь взять любую мелкую, с которой не будет коллизий на выбранной длл.
Или тебе развернуть хэши в чужом коде? Ну так ищи функцию хэширования там, скармливай ей список всех экспортируемых функций из длл и ищи совпадения с твоим хэшем. Для этого обычно пишут скрипт в IDA под конкретный бинарник.
>>284676
> dropbox
Спасибо. Да, 7-Zip-ом и правда не открывается. Странно, на вид вполне обычная импортлиба. В любом случае, dumpbin/podump все нормально дампят.
Для пакмана в виде прямоугольника и точек - пару недель.
s_s segment stack "stack"
dw 12 dup(?)
s_s ends
d_s segment
delitel dw "",0ah,0dh
buffer db 16,0,17 dup(?),"$"
ent dw 0ah,0dh,"$"
d_s ends
c_s segment
assume ss:s_s, ds:d_s, cs:c_s
begin:
mov ax,d_s
mov ds,ax
mov ah,0ch ;очистка буфера
mov al,0
int 21h
mov ah,0ah ;ввод строки
lea dx,buffer
int 21h
mov ah,9h ;delitel
lea dx,ent
int 21h
mov ah,9h ;delitel
lea dx,delitel
int 21h
mov ah,09h ;вывод строки
mov dx,offset buffer+2
int 21h
mov ah,4ch
int 21h
c_s ends
end begin
При выводе строки происходит пикрил т.е. функция 09h выводит не только строку до 0dh включительно, но и не заполненныые элементы массива. ЧЯДНТ?
s_s segment stack "stack"
dw 12 dup(?)
s_s ends
d_s segment
delitel dw "",0ah,0dh
buffer db 16,0,17 dup(?),"$"
ent dw 0ah,0dh,"$"
d_s ends
c_s segment
assume ss:s_s, ds:d_s, cs:c_s
begin:
mov ax,d_s
mov ds,ax
mov ah,0ch ;очистка буфера
mov al,0
int 21h
mov ah,0ah ;ввод строки
lea dx,buffer
int 21h
mov ah,9h ;delitel
lea dx,ent
int 21h
mov ah,9h ;delitel
lea dx,delitel
int 21h
mov ah,09h ;вывод строки
mov dx,offset buffer+2
int 21h
mov ah,4ch
int 21h
c_s ends
end begin
При выводе строки происходит пикрил т.е. функция 09h выводит не только строку до 0dh включительно, но и не заполненныые элементы массива. ЧЯДНТ?
Если пользуешься GNU/Linux дома, рекомендую nasm и методичку Столярова (http://stolyarov.info/books/asm_unix). В принципе, методичка сойдёт и для ваших костылей с tasm & dosbox, кроме прерываний.
> ЧЯДНТ?
Я нихуя не понимаю, что ты вообще делаешь. Почему dw, почему \n\r вместо \r\n, что за delitel dw "", где терминирование введенной строки долларом после ввода? Ты понимаешь, что \d
Что касается спецэффектов - у тебя delitel не терминирован долларом, и это именно он выводит заодно и buffer c мусором. А вывод buffer выводит нихуя, потому что после строки DOS втыкает \r, а \r - это возврат каретки (т.е., вывод продолжается в ТОЙ ЖЕ строке с первой колонки), а после \r нули, которые после возврата каретки затирают все выведенное нахуй. Такие дела.
тогда asmworld.ru тебе по идее хватит.
>>216107 (OP)
Здраститя, я не понел как в отладчиках считается offset почему он 0000 0000 изменяется в 0000 0010 .. 0000 0020 и тд в каких это единицах (в байтах / битах)?
Подскажите пжалста еще какие-нибудь курсы по отладке, пробовал книгу в шапке "Reverse Engineering для начинающих" но она не подошла потому-что я так понимаю надо C хорошо знать и расписано не очень подробно.
> почему он 0000 0000 изменяется в 0000 0010 .. 0000 0020 и тд в каких это единицах (в байтах / битах)?
В байтах. Это шестнадцатеричные числа. 10=16 (десятичное).
И зачем ты джпег отлаживаешь?
изучаю по курсу CrackLab, типо формат файла показывает, он там и txt отлаживает)
> Здраститя, я не понел как в отладчиках считается offset почему он 0000 0000 изменяется в 0000 0010 .. 0000 0020
Не обязательно. В том же HxD у тебя на скрине ты можешь поменять на тулбаре 16 на что-то другое, или вообще нажать ↔, и оно будет адаптировать длину строк к ширине окна. Почему по умолчанию именно 16 (0x10)? Потому что очень удобно иметь дело со степенями двойки. Потому что был реальный режим в x86 с параграфами по 16 байт, т.е., если ты хексдампил сегменты, их адреса и размеры в байтах были выровнены на 16. Потому что строки по 8 байтов (предыдущая степень двойки) были слишком узкие даже для старых мониторов, а строки по 32 байта (следующая степень двойки) в них уже не влезали, они и сейчас-то не у всех влезают, да и искать нужный байт взглядом в таких строках менее удобно.
>>286017
Очевидно, что ответ на вопрос зависит от того, для чего тебе это нужно. Например, ты хочешь ебать железо, или хочешь вкатиться в реверсинг - да, стоит, потому что даже если ты начнешь с Си, тебе все равно придется узнать про существование ассемблера, адресов вместо указателей и всего такого прочего. Если тебе просто кодить на каком-нибудь JS или Python, то лучше не стоит.
Первое интересно,да.
Стоит вкатываться в программирование именно с ассемблера.
>я так понимаю надо C хорошо знать
Надо ассемблер хорошо знать. Читай, писать на нём что-то не самое тривиальное.
Ну что-ж вы, аноны? Какие идеи? Хотя бы пошлите меня куда-нибудь скажите, в какую сторону копать.
Наверное в сторону специальных процессоров.
Тебе уже все сказали. Хочешь неполноценные ядра, работающие синхронно - смотри на GPU, там как раз такое. В нормаольных процах и на нормальных ОС этого не было и не будет, потому что нахуй не нужно.
Зависит от формата. Сегмент у тебя либо уже в cs/ds (если com), либо у него есть имя (если exe). Ну и пишеш:
push 0
pop es ; ES = 0
mov word[es:24h],handle
mov word[es:24h+2],ds_или_имя
А вообще есть функция DOS int 21h/ah=25h, чтобы прерывания перехватывать.
В FASM'е никак нельзя сегмент метки узнать? Например как в других ассемблерах поставить seg, пытался - выдало ошибку
Ну я ж написал, имя есть.
format mz
entry code:start
segment code
start:
...
mov word[es:24h+2],code
А в .com у тебя всегда один сегмент, текущий, он у тебя при запуске программы лежит в сегментных регистрах, во всех трех, выбирай любой.
У меня не com, а загрузчик.
Просто хочу узнать, можно ли средствами FASM узнать сегмент метки, без сегментных регистров, мам, пап и кредитов
Ты не можешь узнать сегмент метки, потому что фасм его не знает. Никто не знает на этапе ассемблирования, в какой сегмент попадет код, когда его запустят. Это узнает... загрузчик исполняемых файлов. В рантайме. И он свои знания кладет в cs/ds/es (com) или (в случае exe), патчит по табличке этими знаниями твой код там, где ты использовал имя сегмента.
> У меня не com, а загрузчик.
Тогда сегмент знаешь ты. Ты же указываешь абсолютный org фасму? Если у тебя стандартный загрузчик под BIOS, который по 0000:7c00h грузится, твой сегмент равен 0 (внезапно, правда?). И опять же, ты можешь узнать его из CS в рантайме, если не веришь мне.
ну, если ты, например, забираешься в чужой процесс и можешь использовать VirtualProtectEx, можешь возле image base пошуршать по таблице импортов и найти адрес, куда был загружен адрес интересующей тебя winapi функции. если этой функции нет, то можешь найти адрес загрузки системной библиотеки в целевой процесс, и уже у него пошуршать в экспортах. если virtual protect использовать не разрешают, то тебе предварительно придется обойти UAC, я где то видел на гитхабе репозиторий с описанием около сотни способов, из которых актуальны процентов 20. если же ты хочешь вообще нахуй разъебать файл библиотеки на диске, то тут если ты придумаешь, как обойти контроль целостности либ тебе надо просто по РЕ структуре пройти и найти свою целевую функцию, заебашить ей детур или чё ты там собрался делать, пересобрать либу, пересчитать контрольную сумму в заголовках файла и в теории твой хук всегда будет в системе
не стоит. ассемблер можно изучить для прикола, когда ты овладел прикладным программированием, но тебе хочется большего. и то, изучать с целью делать небольшие патчи, но писать что то прикладное целиком на ассемблере при наличии высокоуровневых альтернатив - не рационально.
Хорошая рекомендация, потом правда жизни ни на что другое уже не хватит.
я бы советовал определиться с направлением, к которому ты предрасположен
мобайл - java&android sdk для быстрого старта, iOS и языки, поддерживаемые его сдк. java в целом универсальный язык, может еще где пригодится
веб - C# с его .net core/node.js с его js/ts
десктоп - нахуй не нужен уже, но если приложение сложно вынести в веб сервис, то C#&WPF для личных/корпоративных целей, C++ & Qt для коммерческих
IoT, embedded - C/asm, как повезет
ну и реверсинг/ачкеринг - C/C++, asm
С хуя ли Си-пидоры так хейтят GOTO который является аналогом инструкции jump?
Они там ебанулись совсем?
С хуя ли использовать какие-то там jump, если можно срать процессору прямо в instruction pointer? Ишь навыдумывали коллы, реты, джампы какие-то. Функции на этом городят. Ебануться просто.
Всё для вас:
http://wiki.kolibrios.org/wiki/Kernel/ru
Хоть бы указал, мил человек, под какое едро ты компеляеш
>Reverse engineering
Аноны, как вкатиться в это?
Есть технических диплом никому не известного университета, но опыта, знаний нет.
Читаю книгу из оп списка, смотрю видео на ютабе. Но везде требуют 4-5 лет опыта, поиск уязвимостей и тд и тп. Это для борщехлебов или есть компания готовая взять джуном и вырастить его до специалиста. Мне тема интересна, готов вечерами после работы сидеть, но где бы ее еще найти.
Ты сначала реверсить научись.
Надеюсь там можно по F7/F8 трассировать? А не как в, прости господи, gdb.
https://challenges.re/
Я понял, что происходит тут: https://challenges.re/3/
Но нихуя не пойму, что это может быть за алгоритм, нахуя это
тебе что надо конкретнее? есть такая довольно Лоу-лвл книга: https://www.amazon.com/Advanced-Mac-OS-Programming-Guides/dp/0321706250
Спасибо, мил человек, действительно похоже
>>292646
> На crc похоже.
Чем? Наличием таблицы? Лол, да любую байтоеблю можно свести к таблицам. Нет, и близко нет.
1) CRC - это побитовое деление с остатком, т.е., должен быть цикл. Цикла нет.
2) Можно оптимизировать биты до байтов (но цикл останется), тогда будет таблица из 256 (каждое возможное значение байта) слов шириной n бит, где n - степень полинома (для CRC32 - дворды). Тут элементов в таблице явно меньше.
3) CRC предполагает xor (т.к., он там "вместо" сложения используется). Тут xor нет вообще.
Зато тут есть or. И если внимательно посмотреть на код, видно, что оно распространяет (дублирует) установленные биты вправо (сначала по одному, потом по два и так далее):
1001 -> 1101 -> 1111
Фактически, таким образом число округляется вверх до следующей степени двойки - 1 (т.е., 2n - 1 = строка из n единичных битов). Дальше есть два варианта:
1) "Я читал Hacker's Delight", тогда алгоритм вспомнится, или его можно просто найти в книге (несмотря на измененные константы).
2) "Не читал и даже https://graphics.stanford.edu/~seander/bithacks.html не листал". В результате округления, описанного выше, у нас получаются только 32 возможных варианта, можно просто тупо и бездумно протестить каждый, чтобы увидеть паттерн.
Ответ: это branchless реализация clz, которая выдает -1 для отрицательных интов, она даже в вики есть.
> что хочу стать malware-аналитиком
Это как дворник, только еще более скучно и обидно. Если настолько себя не ценишь - лучше иди в вебмакаки.
> выдрочить весь winapi
Windows API не настолько важно, как ядро. И да, миром Windows жизнь не ограничивается.
А что не скучно? В вебмакакинг точно не пойду, если деградировать, то только в по-байтоёбски. Думаю вот между машобом и реверсом.
Так малварь в юзверь-моде сидит же обычно. Винда обуздала петушков с буткитами и теперь они есть только у антивирусных компаний.
> малварь в юзверь-моде сидит же обычно
Но чтобы понимать, что в юзермоде происходит, тебе нужно понимать, как все работает. А все самое интересное делает как раз ядро.
есть одна прога на свифте, скомпилена под арм. В ней захардкожен один ключ. У меня есть исходники проги, но без ключа. Вопрос, можно ли вообще и если да, то как найти этот ключ?
а, в глаза ебусь
хотя действия мне надо сделать подобные - скомпилить прогу с кастомным ключом, который легко найти в бинарном виде например, ввести в поле триста единиц, найти, где он находится в моем бинарнике, а потом найти это же самое место в скачаном бинарнике с ключом.
Траблы только в том, что я ебу как скомпилить иос приложение без мака и айфона.
Ищи строки вокруг ключа, он будет рядом.
https://j00ru.vexillium.org/syscalls/nt/64/
Как обращаться к апи я знаю, но как мне использовать эти системные вызовы напрямую? Что мне делать то с этими байтоёбскими значениями, чтобы получить желаемый результат, без вызова native/win api. С меня тонны нефти.
И еще вопрос. Можно ли это все дело организовать на C++ без использования ассемблерных вставок или все же придется учиться байтоёбскому ремеслу?
Возможно, у кого-то возникнет технический интерес и желание помочь если не делом, то советом.
Я настрочил стену текста на основе того, что уже успел узнать, но она получилась слишком большой, так что вот.
https://pastebin.com/HSWaQPr0
Была идея проследить за данными, которые приходят в сокет, чтоб понять, куда в конце концов попадают команды (после расшифровки, да) и, соответственно, отследить, откуда игра черпает информацию для отображения дальнейших действий. Возможно, это бы пролило свет на природу задержки.
Но пока что не смог реализовать подобное.
> Зачем?
В данном простом примере, да еще и с exit в конце - незачем. А вот если бы ты это в цикле вызывал или из вложенных функций, то тебя ждал бы сюрприз, потому что все функции, которые ты вызываешь - __cdecl, они за собой не чистят, и тебе нужно самому выталкивать из стека все то, что ты туда напихал (на самом деле, нет, просто add esp,скольконапихал).
>тебя ждал бы сюрприз, потому что все функции, которые ты вызываешь - __cdecl, они за собой не чистят
Я так думал, что стек зацикленный. То есть от FFFFFFFF до 00000000, и снова FFFFFFFF. Разве нет?
Ну как бы да, но не в реальной системе с виртуальной памятью. В винде у тебя зарезервированы под стек адреса, ну допустим, 0x00030000-0x00130000 (1 мегабайт), из них выделены при старте процесса только последние 4-8К (адреса и размеры зависят от версии винды и от значений в заголовке exe-шника). Когда ты заполняешь выделенный кусок стека, система тебе выдает еще немного памяти, и так, пока весь зарезервированный регион не кончится. А когда он закончится, ты получаешь исключение по поводу переполнения стека. Но проблема не в этом. Проблема в том, что если ты сделаешь:
hello_message db 'Hello, world!',10,0
main: call hello
push 0
call [exit]
hello: push hello_message
call [puts]
ret
то последний ret прочитает из стека не адрес возврата в main, а адрес hello_message, который никто из стека не убрал. Процессор попытается по нему перейти, начнет выполнять мусор вместо инструкций, и ты упадешь.
>пока весь зарезервированный регион не кончится. А когда он закончится, ты получаешь исключение по поводу переполнения стека
А почему система не может вернуть меня на начало стека при его переполнении?
>поводу переполнения стека
>А почему система не может вернуть меня на начало стека при его переполнении?
Тогда будут затираться данные в начале стека. Если я правильно помню, там лежит адрес вызвавшего процесса, куда должно быть передано управление после того, как твоя программа отработает. Если ты его затрёшь, то пиздец.
Поправьте, если я не прав.
> А почему система не может вернуть меня на начало стека
Потому что это явный баг, и ты потрешь и потеряешь какие-то данные. Поэтому, чтобы не усугублять, ты падаешь (точнее, ты можешь отловить исключение и сделать wraparound, но зачем?).
>>300611
Если мы про винду, то нет - в конце стека адрес заглушки, прибивающей текущий поток (и/или процесс), чтобы возврат из функции по entrypoint завершал программу. Если про DOS, то в начале сегмента CD 20 лежит, оно же int 0x20, оно же местный exit(), а в конце - ret, который возвращает на этот же самый int 0x20.
The constants that can be loaded with these instructions include +1.0, +0.0, log210, loge, π, log2, and log2.
1) stdin line-buffered, т.е., если буфер ввода пуст, то сишный рантайм ждет ввода строки и считывает ее целиком (включая \n на конце).
2) scanf при обработке спецификатора пропускает пробелы до него, но не после, т.е., не вычитывает \n после %d. Можешь очищать буфер каким-нибудь заклинанием уровня https://ideone.com/J0eduZ (извращение, и, к тому же, потребует дополнительную строку, если в буфере УЖЕ пусто). Алсо, чтобы не повторяться >>1291763
3) У тебя не Си, у тебя msvcrt и никакой кроссплатформенности, поэтому можешь пользоваться всякими getch()/getche() и прочими лирше(), которым на буфер похуй. Первый раз в своей жизни агитирую за использование функций из conio.h, и считаю их наилучшим решением проблемы... во всяком случае, пока ты ReadConsole()/SetConsoleMode() не осилишь.
Из того же. Прошу прощения, думал, что экспортируется по-традиции, без подчеркивания.
Все, разобрался, нужно было заменить %f На %lf.
Спасибо.
Анончики подскажите еще одну вещь. Есть ли какие-нибудь годные книги по винде? Желательно что-нибудь свежее + x64.
У сишки для функций с переменным числом аргументов выполняются промоушены, там правил много, но в целом так: все, что меньше int, кастится в int, float кастится к double, остальное как есть. Соответственно, нет никакого способа передать float в функцию с переменным числом аргументов. Как раз поэтому %f для scanf хочет указатель на float (указатель никуда не кастится), а %f для printf хочет дабл и получит дабл, даже если ты передашь float: printf("%f", 1.0f). В ассемблере, естественно, за тебя никто ничего промоутить не будет, и тебе нужно самому об этом заботиться.
https://www.pouet.net/bbs.php?category=code
можно попробовать (если зайдет) demoscene.ru/forum/viewforum.php?f=4
А вообще, IRC, чувачок. Да, IRC до сих пор... В 2018-м ты, конечно устанешь искать канальчики, если тебе просто так не дали. Кое-кто перелез в телеграм. А так инфа, ты не поверишь, до сих пор выходит в виде магов прям на самих платформах.
По pouet'у если поищешь, есть релизы с source code. Начни с мелкотухи в 2^n байт, шанс что ты сделаешь что-то законченное сильно вырастет.
Вы видите копию треда, сохраненную 20 декабря 2018 года.
Скачать тред: только с превью, с превью и прикрепленными файлами.
Второй вариант может долго скачиваться. Файлы будут только в живых или недавно утонувших тредах. Подробнее
Если вам полезен архив М.Двача, пожертвуйте на оплату сервера.