├── .gitignore ├── CommonDemo └── ShowInitOrder │ ├── README.md │ ├── ShowInitOrder.dpr │ ├── ShowInitOrder.dproj │ ├── ShowInitOrder.res │ ├── Unit1.dfm │ ├── Unit1.pas │ ├── UnitInitOrderTracer.pas │ └── img │ └── 1.png ├── Controls ├── FWProgressBar.pas ├── ScaledCtrls.pas └── Shell.TaskBarListProgress.pas ├── LICENSE ├── MemoryMap ├── MemoryMap.Core.pas ├── MemoryMap.DebugMapData.pas ├── MemoryMap.Heaps.pas ├── MemoryMap.ImageHlp.pas ├── MemoryMap.NtDll.pas ├── MemoryMap.PEImage.pas ├── MemoryMap.RegionData.pas ├── MemoryMap.Symbols.pas ├── MemoryMap.Threads.pas ├── MemoryMap.Utils.pas ├── MemoryMap.Workset.pas └── demos │ ├── CallStackCapture │ ├── CallStackCapture.dpr │ ├── CallStackCapture.dproj │ ├── CallStackPG.groupproj │ ├── CallStackTraceUtils.pas │ ├── README.md │ ├── Unit1.dfm │ ├── Unit1.pas │ ├── callstack_library.dpr │ ├── callstack_library.dproj │ └── img │ │ └── callstackcapture.png │ └── CallStackConverter │ ├── CallStackConverter.dpr │ ├── CallStackConverter.dproj │ ├── README.md │ ├── Unit1.dfm │ ├── Unit1.pas │ └── img │ ├── 1.png │ └── 2.png ├── ProcessMM.dpr ├── ProcessMM.dproj ├── ProcessMM.res ├── ProcessMM.stat ├── ProcessMM_Icon.ico ├── ProcessMM_Icon1.ico ├── README.md ├── RawScanner ├── RawScanner.AbstractImage.pas ├── RawScanner.ActivationContext.pas ├── RawScanner.Analyzer.pas ├── RawScanner.ApiSet.pas ├── RawScanner.CoffDwarf.pas ├── RawScanner.Core.pas ├── RawScanner.Disassembler.pas ├── RawScanner.Elf.pas ├── RawScanner.Filter.pas ├── RawScanner.Image.Coff.pas ├── RawScanner.Image.Elf.pas ├── RawScanner.Image.Pe.pas ├── RawScanner.LoaderData.pas ├── RawScanner.Logger.pas ├── RawScanner.MapGenerator.pas ├── RawScanner.SymbolStorage.pas ├── RawScanner.Types.pas ├── RawScanner.Utils.pas ├── RawScanner.Wow64.pas ├── RawScanner.X64Gates.pas ├── demo │ ├── display_utils.pas │ ├── raw_image.dpr │ └── raw_image.dproj └── rawscanner.inc ├── cpu_view.ico ├── distorm ├── 32 │ ├── decoder.obj │ ├── distorm.obj │ ├── instructions.obj │ ├── insts.obj │ ├── mnemonics.obj │ ├── operands.obj │ ├── prefix.obj │ └── textdefs.obj ├── 64 │ ├── decoder.obj │ ├── distorm.obj │ ├── instructions.obj │ ├── insts.obj │ ├── mnemonics.obj │ ├── operands.obj │ ├── prefix.obj │ └── textdefs.obj ├── distorm.pas └── mnemonics.pas ├── doc ├── DWARF4.pdf ├── DWARF5.pdf ├── Dwarf3.pdf ├── dwarf-2.0.0.pdf ├── improving-x64-bin-analysis.pdf ├── ntdll.h └── os-debugging-pdf.pdf ├── img ├── 1.png ├── 10.png ├── 11.png ├── 12.png ├── 14.png ├── 15.png ├── 16.png ├── 2.png ├── 3.png ├── 4.png ├── 5.png ├── 6.png ├── 7.png ├── 8.png └── 9.png ├── plugins ├── include │ ├── pmm_plugin.h │ └── pmm_plugin.pas └── source │ ├── cpp │ └── pmm_rich │ │ ├── pmm_rich.sln │ │ └── source │ │ ├── RichParser.cpp │ │ ├── RichParser.h │ │ ├── dllmain.cpp │ │ ├── exports.def │ │ ├── ext.h │ │ ├── pmm_rich.vcxproj │ │ ├── pmm_rich.vcxproj.filters │ │ └── pmm_rich.vcxproj.user │ ├── delphi │ └── pmm_rich │ │ ├── pmm_rich.dpr │ │ ├── pmm_rich.dproj │ │ ├── pmm_rich.res │ │ └── uRichParser.pas │ └── dwarfreader │ ├── README.md │ ├── dwarfreader.dpr │ ├── dwarfreader.dproj │ └── img │ └── 1.png ├── src ├── gui │ ├── uAbout.dfm │ ├── uAbout.pas │ ├── uBaseForm.dfm │ ├── uBaseForm.pas │ ├── uCallStack.dfm │ ├── uCallStack.pas │ ├── uComparator.dfm │ ├── uComparator.pas │ ├── uDebugInfoDlg.dfm │ ├── uDebugInfoDlg.pas │ ├── uExportList.dfm │ ├── uExportList.pas │ ├── uFindData.dfm │ ├── uFindData.pas │ ├── uKnownData.dfm │ ├── uKnownData.pas │ ├── uMemoryMapListInfo.dfm │ ├── uMemoryMapListInfo.pas │ ├── uMemoryMapListInfoSettings.dfm │ ├── uMemoryMapListInfoSettings.pas │ ├── uPatchDetect.dfm │ ├── uPatchDetect.pas │ ├── uProcessMM.dfm │ ├── uProcessMM.pas │ ├── uProgress.dfm │ ├── uProgress.pas │ ├── uRegionProperties.dfm │ ├── uRegionProperties.pas │ ├── uSearchResult.dfm │ ├── uSearchResult.pas │ ├── uSelectAddress.dfm │ ├── uSelectAddress.pas │ ├── uSelectProcess.dfm │ ├── uSelectProcess.pas │ ├── uSettings.dfm │ ├── uSettings.pas │ ├── uStringsViewer.dfm │ └── uStringsViewer.pas ├── uDisplayUtils.pas ├── uDump.pas ├── uDumpDisplayUtils.pas ├── uIPC.pas ├── uPluginManager.pas ├── uProcessReconnect.pas └── uUtils.pas ├── updates.txt ├── win64debug.rc └── win64release.rc /.gitignore: -------------------------------------------------------------------------------- 1 | *.dcu 2 | *.~*~ 3 | *.local 4 | *.identcache 5 | __history 6 | *.drc 7 | *.map 8 | *.exe 9 | *.dll 10 | bin/* 11 | *.skincfg 12 | *.rsm 13 | *.~* -------------------------------------------------------------------------------- /CommonDemo/ShowInitOrder/README.md: -------------------------------------------------------------------------------- 1 | Show Delphi/Lazarus Unit Init Order 2 | ================ 3 | 4 | Демонстрация работы с классами TDebugMap, TRawPEImage, TRawScannerSymbolStorage и TDisassembler. 5 | Демо-пример реализует вывод списка используемых модулей в порядке их инициализации, включая вызовы классовых конструкторов/деструкторов. 6 | 7 | ### Внешний вид: 8 | 9 | ![1](https://github.com/AlexanderBagel/ProcessMemoryMap/blob/master/CommonDemo/ShowInitOrder/img/1.png?raw=true "Внешний вид") 10 | 11 | ### Принцип работы 12 | 13 | В отладочной информации Delphi, конкретно в МАР файле отсутствует информация об адресе таблицы инициализации модулей, поэтому реализована функция LoadDelphiUnitInitOrder, 14 | в которой дизассемблируется точка входа в приложение и производится поиск вызова функции "@InitExe" или "SysInit.@InitExe". 15 | Данной функции на вход передается адрес заголовка таблицы инициализации, получив который производится парсинг таблицы. 16 | 17 | В версии для Lazarus (функция LoadLazarusUnitInitOrder), адрес таблицы инициализации изначально присутствует в отладочных COFF символах под именем "INITFINAL". 18 | Но, в отличии от Delphi, данная таблица инициализации не содержит вызовов классовых конструкторов/деструкторов. 19 | Они распологаются в функции инициализации того модуля, где обьявлен класс. Поэтому для определения вызовов классов конструкторов приозводится дизассемблирование 20 | каждой процедуры инициализации/финализации с целью поиска таких вызовов. 21 | Пока что разбор происходит только на основании COFF информации и в результат могут ошибочно попадать вызовы обычных конструкторов/деструкторов классов. 22 | Как только будет подключен полный пакет DWARF информации, ошибочные вызовы должны быть исключены. 23 | -------------------------------------------------------------------------------- /CommonDemo/ShowInitOrder/ShowInitOrder.dpr: -------------------------------------------------------------------------------- 1 | program ShowInitOrder; 2 | 3 | uses 4 | Vcl.Forms, 5 | Unit1 in 'Unit1.pas' {frmShowInitOrder}, 6 | UnitInitOrderTracer in 'UnitInitOrderTracer.pas', 7 | MemoryMap.DebugMapData in '..\..\MemoryMap\MemoryMap.DebugMapData.pas', 8 | MemoryMap.ImageHlp in '..\..\MemoryMap\MemoryMap.ImageHlp.pas', 9 | MemoryMap.NtDll in '..\..\MemoryMap\MemoryMap.NtDll.pas', 10 | MemoryMap.PEImage in '..\..\MemoryMap\MemoryMap.PEImage.pas', 11 | MemoryMap.Symbols in '..\..\MemoryMap\MemoryMap.Symbols.pas', 12 | MemoryMap.Utils in '..\..\MemoryMap\MemoryMap.Utils.pas', 13 | RawScanner.CoffDwarf in '..\..\RawScanner\RawScanner.CoffDwarf.pas', 14 | RawScanner.Disassembler in '..\..\RawScanner\RawScanner.Disassembler.pas', 15 | RawScanner.SymbolStorage in '..\..\RawScanner\RawScanner.SymbolStorage.pas', 16 | RawScanner.Types in '..\..\RawScanner\RawScanner.Types.pas', 17 | distorm in '..\..\distorm\distorm.pas', 18 | mnemonics in '..\..\distorm\mnemonics.pas', 19 | RawScanner.Logger in '..\..\RawScanner\RawScanner.Logger.pas', 20 | RawScanner.Utils in '..\..\RawScanner\RawScanner.Utils.pas', 21 | RawScanner.Wow64 in '..\..\RawScanner\RawScanner.Wow64.pas', 22 | RawScanner.X64Gates in '..\..\RawScanner\RawScanner.X64Gates.pas', 23 | RawScanner.ApiSet in '..\..\RawScanner\RawScanner.ApiSet.pas', 24 | RawScanner.Image.Pe in '..\..\RawScanner\RawScanner.Image.Pe.pas', 25 | RawScanner.AbstractImage in '..\..\RawScanner\RawScanner.AbstractImage.pas'; 26 | 27 | {$R *.res} 28 | 29 | begin 30 | Application.Initialize; 31 | Application.MainFormOnTaskbar := True; 32 | Application.CreateForm(TfrmShowInitOrder, frmShowInitOrder); 33 | Application.Run; 34 | end. 35 | -------------------------------------------------------------------------------- /CommonDemo/ShowInitOrder/ShowInitOrder.res: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexanderBagel/ProcessMemoryMap/c5dc46ff63fb0fa20f6728abed0214786f91e4a2/CommonDemo/ShowInitOrder/ShowInitOrder.res -------------------------------------------------------------------------------- /CommonDemo/ShowInitOrder/Unit1.dfm: -------------------------------------------------------------------------------- 1 | object frmShowInitOrder: TfrmShowInitOrder 2 | Left = 0 3 | Top = 0 4 | Caption = 'Show Delphi/Lazarus Unit Init Order' 5 | ClientHeight = 421 6 | ClientWidth = 757 7 | Color = clBtnFace 8 | Font.Charset = DEFAULT_CHARSET 9 | Font.Color = clWindowText 10 | Font.Height = -11 11 | Font.Name = 'Tahoma' 12 | Font.Style = [] 13 | OldCreateOrder = False 14 | Position = poScreenCenter 15 | OnCreate = FormCreate 16 | DesignSize = ( 17 | 757 18 | 421) 19 | PixelsPerInch = 96 20 | TextHeight = 13 21 | object lePath: TLabeledEdit 22 | Left = 8 23 | Top = 24 24 | Width = 579 25 | Height = 21 26 | Anchors = [akLeft, akTop, akRight] 27 | EditLabel.Width = 82 28 | EditLabel.Height = 13 29 | EditLabel.Caption = 'Executable path:' 30 | TabOrder = 0 31 | OnChange = lePathChange 32 | end 33 | object btnBrowse: TButton 34 | Left = 593 35 | Top = 22 36 | Width = 75 37 | Height = 25 38 | Anchors = [akTop, akRight] 39 | Caption = 'Browse...' 40 | TabOrder = 1 41 | OnClick = btnBrowseClick 42 | end 43 | object btnLoad: TButton 44 | Left = 674 45 | Top = 22 46 | Width = 75 47 | Height = 25 48 | Anchors = [akTop, akRight] 49 | Caption = 'Load' 50 | Enabled = False 51 | TabOrder = 2 52 | OnClick = btnLoadClick 53 | end 54 | object lvReport: TListView 55 | Left = 8 56 | Top = 51 57 | Width = 741 58 | Height = 307 59 | Anchors = [akLeft, akTop, akRight, akBottom] 60 | Columns = < 61 | item 62 | Caption = #8470 63 | end 64 | item 65 | AutoSize = True 66 | Caption = 'UnitName' 67 | end 68 | item 69 | Caption = 'Type' 70 | Width = 75 71 | end 72 | item 73 | Caption = 'InitVA' 74 | Width = 100 75 | end 76 | item 77 | Caption = 'FinallyVA' 78 | Width = 100 79 | end> 80 | DoubleBuffered = True 81 | HideSelection = False 82 | HotTrack = True 83 | ReadOnly = True 84 | RowSelect = True 85 | ParentDoubleBuffered = False 86 | PopupMenu = pmCopy 87 | TabOrder = 3 88 | ViewStyle = vsReport 89 | OnCustomDrawItem = lvReportCustomDrawItem 90 | end 91 | object memLog: TMemo 92 | Left = 8 93 | Top = 364 94 | Width = 741 95 | Height = 49 96 | Anchors = [akLeft, akRight, akBottom] 97 | ReadOnly = True 98 | ScrollBars = ssVertical 99 | TabOrder = 4 100 | end 101 | object OpenDialog: TOpenDialog 102 | DefaultExt = '.exe' 103 | Filter = 'Executable Files (*.exe)|*.exe|All Files (*.*)|*.*' 104 | Left = 360 105 | Top = 232 106 | end 107 | object pmCopy: TPopupMenu 108 | OnPopup = pmCopyPopup 109 | Left = 440 110 | Top = 232 111 | object mnuCopyLine: TMenuItem 112 | Caption = 'Copy Line' 113 | OnClick = mnuCopyLineClick 114 | end 115 | object mnuCopyUnit: TMenuItem 116 | Caption = 'Copy Unit Name' 117 | OnClick = mnuCopyUnitClick 118 | end 119 | object mnuCopyInit: TMenuItem 120 | Tag = 2 121 | Caption = 'Copy Initialization address' 122 | OnClick = mnuCopyUnitClick 123 | end 124 | object mnuCopyFin: TMenuItem 125 | Tag = 3 126 | Caption = 'Copy finalization address' 127 | OnClick = mnuCopyUnitClick 128 | end 129 | object N1: TMenuItem 130 | Caption = '-' 131 | end 132 | object CopyUnitInitializationOrder1: TMenuItem 133 | Caption = 'Copy Unit Initialization Order' 134 | OnClick = CopyUnitInitializationOrder1Click 135 | end 136 | object CopyAll2: TMenuItem 137 | Caption = '-' 138 | end 139 | object mnuCopyAll: TMenuItem 140 | Caption = 'Copy All' 141 | OnClick = mnuCopyAllClick 142 | end 143 | end 144 | end 145 | -------------------------------------------------------------------------------- /CommonDemo/ShowInitOrder/Unit1.pas: -------------------------------------------------------------------------------- 1 | unit Unit1; 2 | 3 | interface 4 | 5 | uses 6 | Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, 7 | Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.ExtCtrls, Vcl.ComCtrls, 8 | Vcl.Menus, Clipbrd; 9 | 10 | type 11 | TfrmShowInitOrder = class(TForm) 12 | lePath: TLabeledEdit; 13 | btnBrowse: TButton; 14 | btnLoad: TButton; 15 | OpenDialog: TOpenDialog; 16 | lvReport: TListView; 17 | memLog: TMemo; 18 | pmCopy: TPopupMenu; 19 | mnuCopyLine: TMenuItem; 20 | mnuCopyUnit: TMenuItem; 21 | mnuCopyInit: TMenuItem; 22 | mnuCopyFin: TMenuItem; 23 | N1: TMenuItem; 24 | CopyUnitInitializationOrder1: TMenuItem; 25 | mnuCopyAll: TMenuItem; 26 | CopyAll2: TMenuItem; 27 | procedure lePathChange(Sender: TObject); 28 | procedure btnBrowseClick(Sender: TObject); 29 | procedure btnLoadClick(Sender: TObject); 30 | procedure lvReportCustomDrawItem(Sender: TCustomListView; Item: TListItem; 31 | State: TCustomDrawState; var DefaultDraw: Boolean); 32 | procedure pmCopyPopup(Sender: TObject); 33 | procedure mnuCopyLineClick(Sender: TObject); 34 | procedure mnuCopyUnitClick(Sender: TObject); 35 | procedure CopyUnitInitializationOrder1Click(Sender: TObject); 36 | procedure FormCreate(Sender: TObject); 37 | procedure mnuCopyAllClick(Sender: TObject); 38 | private 39 | { Private declarations } 40 | public 41 | { Public declarations } 42 | end; 43 | 44 | var 45 | frmShowInitOrder: TfrmShowInitOrder; 46 | 47 | implementation 48 | 49 | uses 50 | UnitInitOrderTracer; 51 | 52 | {$R *.dfm} 53 | 54 | procedure TfrmShowInitOrder.btnBrowseClick(Sender: TObject); 55 | begin 56 | if OpenDialog.Execute(Handle) then 57 | lePath.Text := OpenDialog.FileName; 58 | end; 59 | 60 | procedure TfrmShowInitOrder.btnLoadClick(Sender: TObject); 61 | var 62 | List: TUnitInitOrderList; 63 | ListType: TOrderListType; 64 | AUnit: TUnitData; 65 | CenterIndex: Integer; 66 | UnitName, AType: string; 67 | AItem: TListItem; 68 | begin 69 | memLog.Clear; 70 | memLog.Lines.Add('Process: ' + lePath.Text); 71 | try 72 | List := GetUnitInitOrderList(lePath.Text, ListType); 73 | try 74 | lvReport.Items.BeginUpdate; 75 | try 76 | lvReport.Clear; 77 | for AUnit in List do 78 | begin 79 | UnitName := AUnit.UnitName; 80 | AType := 'Unit'; 81 | 82 | case ListType of 83 | oltDelphi: 84 | begin 85 | if AUnit.InitializarionVA = 0 then 86 | AType := 'System' 87 | end; 88 | oltDelphiWithNamespaces: 89 | begin 90 | // для модулей процедура инициализации выглядит как "имя модуля"."имя модуля" 91 | // поэтому просто сверяем по центральной точке совпадение обоих частей и 92 | // если совпало - убираем лишнее 93 | CenterIndex := Length(UnitName) div 2; 94 | if Copy(UnitName, 1, CenterIndex) = Copy(UnitName, CenterIndex + 2, CenterIndex) then 95 | SetLength(UnitName, CenterIndex) 96 | else 97 | if (UnitName <> '') and (UnitName[Length(UnitName)] = '@') then 98 | AType := 'Class' 99 | else 100 | AType := 'System'; 101 | end; 102 | oltLazarus: 103 | begin 104 | if AUnit.FpcClass then 105 | if Pos('.', AUnit.UnitName) > 0 then 106 | AType := 'Class' 107 | else 108 | AType := 'System'; 109 | end; 110 | end; 111 | 112 | AItem := lvReport.Items.Add; 113 | AItem.Caption := IntToStr(lvReport.Items.Count); 114 | AItem.SubItems.Add(UnitName); 115 | AItem.SubItems.Add(AType); 116 | AItem.SubItems.Add('0x' + IntToHex(AUnit.InitializarionVA, 1)); 117 | AItem.SubItems.Add('0x' + IntToHex(AUnit.FinalizationVA, 1)); 118 | end; 119 | finally 120 | lvReport.Items.EndUpdate; 121 | end; 122 | finally 123 | List.Free; 124 | end; 125 | except 126 | on E: Exception do 127 | memLog.Lines.Add(E.ClassName + ': ' + E.Message); 128 | end; 129 | memLog.Lines.Add('Done. Count: ' + IntToStr(lvReport.Items.Count)); 130 | end; 131 | 132 | procedure TfrmShowInitOrder.CopyUnitInitializationOrder1Click(Sender: TObject); 133 | var 134 | S: string; 135 | begin 136 | for var Item in lvReport.Items do 137 | if Item.SubItems[1] = 'Unit' then 138 | S := S + sLineBreak + Item.SubItems[0]; 139 | Clipboard.AsText := Trim(S); 140 | end; 141 | 142 | procedure TfrmShowInitOrder.FormCreate(Sender: TObject); 143 | begin 144 | if IsDebuggerPresent then 145 | lePath.Text := ParamStr(0); 146 | end; 147 | 148 | procedure TfrmShowInitOrder.lePathChange(Sender: TObject); 149 | begin 150 | btnLoad.Enabled := FileExists(lePath.Text); 151 | end; 152 | 153 | procedure TfrmShowInitOrder.lvReportCustomDrawItem(Sender: TCustomListView; 154 | Item: TListItem; State: TCustomDrawState; var DefaultDraw: Boolean); 155 | begin 156 | if Item.SubItems[1] = 'System' then 157 | lvReport.Canvas.Brush.Color := $B092EC; 158 | if Item.SubItems[1] = 'Class' then 159 | lvReport.Canvas.Brush.Color := $E4C4CF; 160 | end; 161 | 162 | procedure TfrmShowInitOrder.mnuCopyAllClick(Sender: TObject); 163 | var 164 | S: string; 165 | begin 166 | for var Item in lvReport.Items do 167 | begin 168 | S := S + sLineBreak + Format('%s'#9'%s'#9'%s'#9'%s'#9'%s', 169 | [ 170 | Item.Caption, 171 | Item.SubItems[0], 172 | Item.SubItems[1], 173 | Item.SubItems[2], 174 | Item.SubItems[3] 175 | ]); 176 | end; 177 | Clipboard.AsText := Trim(S); 178 | end; 179 | 180 | procedure TfrmShowInitOrder.mnuCopyLineClick(Sender: TObject); 181 | begin 182 | Clipboard.AsText := Format('%s'#9'%s'#9'%s'#9'%s'#9'%s', 183 | [ 184 | lvReport.Selected.Caption, 185 | lvReport.Selected.SubItems[0], 186 | lvReport.Selected.SubItems[1], 187 | lvReport.Selected.SubItems[2], 188 | lvReport.Selected.SubItems[3] 189 | ]); 190 | end; 191 | 192 | procedure TfrmShowInitOrder.mnuCopyUnitClick(Sender: TObject); 193 | begin 194 | Clipboard.AsText := lvReport.Selected.SubItems[TMenuItem(Sender).Tag]; 195 | end; 196 | 197 | procedure TfrmShowInitOrder.pmCopyPopup(Sender: TObject); 198 | begin 199 | mnuCopyLine.Enabled := lvReport.Selected <> nil; 200 | mnuCopyUnit.Enabled := mnuCopyLine.Enabled; 201 | mnuCopyInit.Enabled := mnuCopyLine.Enabled; 202 | mnuCopyFin.Enabled := mnuCopyLine.Enabled; 203 | end; 204 | 205 | end. 206 | -------------------------------------------------------------------------------- /CommonDemo/ShowInitOrder/img/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexanderBagel/ProcessMemoryMap/c5dc46ff63fb0fa20f6728abed0214786f91e4a2/CommonDemo/ShowInitOrder/img/1.png -------------------------------------------------------------------------------- /Controls/ScaledCtrls.pas: -------------------------------------------------------------------------------- 1 | unit ScaledCtrls; 2 | 3 | interface 4 | 5 | uses 6 | Windows, 7 | Graphics, 8 | Controls, 9 | ComCtrls; 10 | 11 | type 12 | TScaledIcon = class(TIcon) 13 | protected 14 | procedure Draw(ACanvas: TCanvas; const Rect: TRect); override; 15 | end; 16 | 17 | TRichEdit = class(ComCtrls.TRichEdit) 18 | protected 19 | function DefaultScalingFlags: TScalingFlags; override; 20 | end; 21 | 22 | implementation 23 | 24 | { TScaledIcon } 25 | 26 | procedure TScaledIcon.Draw(ACanvas: TCanvas; const Rect: TRect); 27 | begin 28 | if (Rect.Width = Width) and (Rect.Height = Height) then 29 | inherited 30 | else 31 | with Rect do 32 | DrawIconEx(ACanvas.Handle, Left, Top, Handle, 33 | Rect.Width, Rect.Height, 0, 0, DI_NORMAL); 34 | end; 35 | 36 | { TRichEdit } 37 | 38 | function TRichEdit.DefaultScalingFlags: TScalingFlags; 39 | begin 40 | Result := inherited + [sfFont]; 41 | end; 42 | 43 | end. 44 | -------------------------------------------------------------------------------- /MemoryMap/MemoryMap.ImageHlp.pas: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // **************************************************************************** 4 | // * Project : MemoryMap 5 | // * Unit Name : MemoryMap.ImageHlp.pas 6 | // * Purpose : Класс фиксит ошибки ImageHlp в Delphi 10.4 7 | // * Author : Александр (Rouse_) Багель 8 | // * Copyright : © Fangorn Wizards Lab 1998 - 2023. 9 | // * Version : 1.4.34 10 | // * Home Page : http://rouse.drkb.ru 11 | // * Home Blog : http://alexander-bagel.blogspot.ru 12 | // **************************************************************************** 13 | // * Stable Release : http://rouse.drkb.ru/winapi.php#pmm2 14 | // * Latest Source : https://github.com/AlexanderBagel/ProcessMemoryMap 15 | // **************************************************************************** 16 | // 17 | 18 | unit MemoryMap.ImageHlp; 19 | 20 | interface 21 | 22 | uses 23 | Windows, 24 | ImageHlp; 25 | 26 | const 27 | ImagehlpLib = 'IMAGEHLP.DLL'; 28 | 29 | type 30 | // Delphi BUG!!! 31 | // Wrong record alignment!!! 32 | PloadedImage = ^TLoadedImage; 33 | {$EXTERNALSYM _LOADED_IMAGE} 34 | _LOADED_IMAGE = record 35 | ModuleName: LPSTR; 36 | hFile: THandle; 37 | MappedAddress: PChar; 38 | FileHeader: PImageNtHeaders; 39 | LastRvaSection: PImageSectionHeader; 40 | NumberOfSections: ULONG; 41 | Sections: PImageSectionHeader; 42 | Characteristics: ULONG; 43 | fSystemImage: ByteBool; 44 | fDOSImage: ByteBool; 45 | 46 | //Links: TListEntry; WRONG ONE poiner record with align 16 47 | Links: LIST_ENTRY; // Valid two pointer record 48 | 49 | SizeOfImage: ULONG; 50 | end; 51 | {$EXTERNALSYM LOADED_IMAGE} 52 | LOADED_IMAGE = _LOADED_IMAGE; 53 | LoadedImage = _LOADED_IMAGE; 54 | TLoadedImage = _Loaded_IMAGE; 55 | 56 | function MapAndLoad(ImageName, DllPath: LPSTR; LoadedImage: PLoadedImage; 57 | DotDll, ReadOnly: Bool): Bool; stdcall; external ImagehlpLib; 58 | 59 | function ImageDirectoryEntryToData(Base: Pointer; MappedAsImage: ByteBool; 60 | DirectoryEntry: Word; var Size: ULONG): Pointer; stdcall; external ImagehlpLib; 61 | 62 | function UnMapAndLoad(LoadedImage: PLoadedImage): Bool; stdcall; external ImagehlpLib; 63 | 64 | type 65 | PImagehlpSymbol = ^TImagehlpSymbol; 66 | _IMAGEHLP_SYMBOL = record 67 | SizeOfStruct: DWORD; 68 | Address: NativeUInt; 69 | Size, 70 | Flags, 71 | MaxNameLength: DWORD; 72 | Name: packed array[0..0] of Byte; 73 | end; 74 | TImagehlpSymbol = _IMAGEHLP_SYMBOL; 75 | 76 | {$IFDEF WIN64} 77 | function SymGetSymFromAddr(hProcess: THandle; dwAddr: ULONG_PTR; 78 | pdwDisplacement: PDWORD64; Symbol: PImagehlpSymbol): Bool; stdcall; 79 | external ImagehlpLib name 'SymGetSymFromAddr64'; 80 | function SymLoadModule(hProcess: THandle; hFile: THandle; ImageName, 81 | ModuleName: LPSTR; BaseOfDll: ULONG_PTR; SizeOfDll: DWORD): DWORD; stdcall; 82 | external ImagehlpLib name 'SymLoadModule64'; 83 | function SymUnloadModule(hProcess: THandle; BaseOfDll: ULONG_PTR): Bool; stdcall; 84 | external ImagehlpLib name 'SymUnloadModule64'; 85 | function SymEnumerateSymbols(hProcess: THandle; BaseOfDll: ULONG_PTR; 86 | EnumSymbolsCallback: TSymEnumSymbolsCallback; UserContext: Pointer): Bool; stdcall; 87 | external ImagehlpLib name 'SymEnumerateSymbols64'; 88 | function SymUnDName(Symbol: PImagehlpSymbol; UnDecName: PChar; UnDecNameLength: DWORD): Bool; stdcall; 89 | external ImagehlpLib name 'SymUnDName64'; 90 | {$ELSE} 91 | function SymGetSymFromAddr(hProcess: THandle; dwAddr: ULONG_PTR; 92 | pdwDisplacement: PDWORD; Symbol: PImagehlpSymbol): Bool; stdcall; 93 | external ImagehlpLib; 94 | function SymLoadModule(hProcess: THandle; hFile: THandle; ImageName, 95 | ModuleName: LPSTR; BaseOfDll: ULONG_PTR; SizeOfDll: DWORD): DWORD; stdcall; 96 | external ImagehlpLib; 97 | function SymUnloadModule(hProcess: THandle; BaseOfDll: ULONG_PTR): Bool; stdcall; 98 | external ImagehlpLib; 99 | function SymEnumerateSymbols(hProcess: THandle; BaseOfDll: ULONG_PTR; 100 | EnumSymbolsCallback: TSymEnumSymbolsCallback; UserContext: Pointer): Bool; stdcall; 101 | external ImagehlpLib; 102 | function SymUnDName(Symbol: PImagehlpSymbol; UnDecName: PChar; UnDecNameLength: DWORD): Bool; stdcall; 103 | external ImagehlpLib; 104 | {$ENDIF} 105 | 106 | { options that are set/returned by SymSetOptions() & SymGetOptions() } 107 | { these are used as a mask } 108 | 109 | const 110 | {$EXTERNALSYM SYMOPT_CASE_INSENSITIVE} 111 | SYMOPT_CASE_INSENSITIVE = $00000001; 112 | {$EXTERNALSYM SYMOPT_UNDNAME} 113 | SYMOPT_UNDNAME = $00000002; 114 | {$EXTERNALSYM SYMOPT_DEFERRED_LOADS} 115 | SYMOPT_DEFERRED_LOADS = $00000004; 116 | {$EXTERNALSYM SYMOPT_NO_CPP} 117 | SYMOPT_NO_CPP = $00000008; 118 | 119 | 120 | {$EXTERNALSYM SymSetOptions} 121 | function SymSetOptions(SymOptions: DWORD): DWORD; stdcall; external ImagehlpLib; 122 | 123 | {$EXTERNALSYM SymSetOptions} 124 | function SymGetOptions: DWORD; stdcall; external ImagehlpLib; 125 | 126 | {$EXTERNALSYM SymInitialize} 127 | function SymInitialize(hProcess: THandle; UserSearchPath: LPSTR; 128 | fInvadeProcess: Bool): Bool; stdcall; external ImagehlpLib; 129 | 130 | {$EXTERNALSYM SymCleanup} 131 | function SymCleanup(hProcess: THandle): Bool; stdcall; external ImagehlpLib; 132 | 133 | implementation 134 | 135 | end. 136 | -------------------------------------------------------------------------------- /MemoryMap/MemoryMap.Workset.pas: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // **************************************************************************** 4 | // * Project : MemoryMap 5 | // * Unit Name : MemoryMap.Workset.pas 6 | // * Purpose : Класс собирает данные о Workset процесса 7 | // * Author : Александр (Rouse_) Багель 8 | // * Copyright : © Fangorn Wizards Lab 1998 - 2022. 9 | // * Version : 1.3.21 10 | // * Home Page : http://rouse.drkb.ru 11 | // * Home Blog : http://alexander-bagel.blogspot.ru 12 | // **************************************************************************** 13 | // * Stable Release : http://rouse.drkb.ru/winapi.php#pmm2 14 | // * Latest Source : https://github.com/AlexanderBagel/ProcessMemoryMap 15 | // **************************************************************************** 16 | // 17 | 18 | unit MemoryMap.Workset; 19 | 20 | interface 21 | 22 | uses 23 | Winapi.Windows, 24 | Winapi.PsAPI, 25 | System.SysUtils, 26 | Generics.Collections; 27 | 28 | type 29 | TShareInfo = record 30 | Shared: Boolean; 31 | SharedCount: Byte; 32 | end; 33 | 34 | TWorkset = class 35 | private 36 | FData: TDictionary; 37 | protected 38 | procedure InitWorksetData(hProcess: THandle); 39 | public 40 | constructor Create(hProcess: THandle); 41 | destructor Destroy; override; 42 | function GetPageSharedInfo(pPage: Pointer; var Shared: Boolean; 43 | var SharedCount: Byte): Boolean; 44 | end; 45 | 46 | implementation 47 | 48 | { TWorkset } 49 | 50 | constructor TWorkset.Create(hProcess: THandle); 51 | begin 52 | FData := TDictionary.Create; 53 | InitWorksetData(hProcess); 54 | end; 55 | 56 | destructor TWorkset.Destroy; 57 | begin 58 | FData.Free; 59 | inherited; 60 | end; 61 | 62 | function TWorkset.GetPageSharedInfo(pPage: Pointer; var Shared: Boolean; 63 | var SharedCount: Byte): Boolean; 64 | var 65 | ShareInfo: TShareInfo; 66 | begin 67 | Result := FData.TryGetValue(pPage, ShareInfo); 68 | if Result then 69 | begin 70 | Shared := ShareInfo.Shared; 71 | SharedCount := ShareInfo.SharedCount; 72 | end; 73 | end; 74 | 75 | procedure TWorkset.InitWorksetData(hProcess: THandle); 76 | const 77 | {$IFDEF WIN64} 78 | AddrMask = $FFFFFFFFFFFFF000; 79 | {$ELSE} 80 | AddrMask = $FFFFF000; 81 | {$ENDIF} 82 | SharedBitMask = $100; 83 | SharedCountMask = $E0; 84 | 85 | function GetSharedCount(Value: ULONG_PTR): Byte; inline; 86 | begin 87 | Result := (Value and SharedCountMask) shr 5; 88 | end; 89 | 90 | var 91 | WorksetBuff: array of ULONG_PTR; 92 | I: Integer; 93 | ShareInfo: TShareInfo; 94 | begin 95 | SetLength(WorksetBuff, $400000); 96 | while not QueryWorkingSet(hProcess, @WorksetBuff[0], 97 | Length(WorksetBuff) * SizeOf(ULONG_PTR)) do 98 | begin 99 | if WorksetBuff[0] = 0 then Exit; 100 | SetLength(WorksetBuff, WorksetBuff[0] * 2); 101 | end; 102 | 103 | for I := 0 to WorksetBuff[0] - 1 do 104 | begin 105 | ShareInfo.Shared := WorksetBuff[I] and SharedBitMask <> 0; 106 | ShareInfo.SharedCount := GetSharedCount(WorksetBuff[I]); 107 | try 108 | FData.AddOrSetValue(Pointer(WorksetBuff[I] and AddrMask), ShareInfo); 109 | except 110 | on E: EListError do ; 111 | else 112 | raise; 113 | end; 114 | end; 115 | end; 116 | 117 | end. 118 | -------------------------------------------------------------------------------- /MemoryMap/demos/CallStackCapture/CallStackCapture.dpr: -------------------------------------------------------------------------------- 1 | program CallStackCapture; 2 | 3 | uses 4 | Vcl.Forms, 5 | Unit1 in 'Unit1.pas' {Form1}, 6 | CallStackTraceUtils in 'CallStackTraceUtils.pas', 7 | MemoryMap.DebugMapData in '..\..\MemoryMap.DebugMapData.pas', 8 | MemoryMap.PEImage in '..\..\MemoryMap.PEImage.pas', 9 | MemoryMap.Utils in '..\..\MemoryMap.Utils.pas', 10 | MemoryMap.ImageHlp in '..\..\MemoryMap.ImageHlp.pas', 11 | MemoryMap.NtDll in '..\..\MemoryMap.NtDll.pas', 12 | MemoryMap.Symbols in '..\..\MemoryMap.Symbols.pas'; 13 | 14 | {$R *.res} 15 | 16 | begin 17 | Application.Initialize; 18 | Application.MainFormOnTaskbar := True; 19 | Application.CreateForm(TForm1, Form1); 20 | Application.Run; 21 | end. 22 | -------------------------------------------------------------------------------- /MemoryMap/demos/CallStackCapture/CallStackPG.groupproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | {9654A544-229E-4922-8061-43D53CC78112} 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | Default.Personality.12 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /MemoryMap/demos/CallStackCapture/CallStackTraceUtils.pas: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // **************************************************************************** 4 | // * Unit Name : CallStackTraceUtils 5 | // * Purpose : Реализация дампа текущего стека вызовов 6 | // * Author : Александр (Rouse_) Багель 7 | // * Version : 1.01 8 | // **************************************************************************** 9 | // 10 | 11 | unit CallStackTraceUtils; 12 | 13 | interface 14 | 15 | uses 16 | Windows, 17 | Classes, 18 | SysUtils, 19 | PsAPI, 20 | MemoryMap.Symbols, 21 | MemoryMap.DebugMapData, 22 | MemoryMap.Utils; 23 | 24 | function GetCallStack(FramesCount: Integer = 128): TStringList; 25 | 26 | implementation 27 | 28 | function RtlCaptureStackBackTrace(FramesToSkip, FramesToCapture: ULONG; 29 | BackTrace: PPVOID; BackTraceHash: PULONG): USHORT; stdcall; external kernel32; 30 | 31 | function EnumProcessModulesEx(hProcess: THandle; lphModule: PHandle; 32 | cb: DWORD; var lpcbNeeded: DWORD; dwFilterFlag: DWORD): BOOL; stdcall; 33 | external 'psapi.dll'; 34 | 35 | function GetBaseAddr(AAddress: NativeUInt): NativeUInt; 36 | var 37 | Info: TMemoryBasicInformation; 38 | begin 39 | if VirtualQuery(Pointer(AAddress), Info, SizeOf(TMemoryBasicInformation)) <> 0 then 40 | Result := NativeUInt(Info.BaseAddress) 41 | else 42 | Result := 0; 43 | end; 44 | 45 | function GetModuleNameFromAddr(AAddress: NativeUInt): string; 46 | var 47 | Len: Cardinal; 48 | begin 49 | SetLength(Result, MAX_PATH); 50 | Len := GetMappedFileName(GetCurrentProcess, Pointer(AAddress), 51 | @Result[1], MAX_PATH); 52 | SetLength(Result, Len); 53 | Result := NormalizePath(Result); 54 | end; 55 | 56 | function GetFunction(const Value: string): string; 57 | var 58 | Index: Integer; 59 | begin 60 | Index := Pos('+', Value); 61 | if Index > 0 then 62 | Result := Trim(Copy(Value, 1, Index - 1)) 63 | else 64 | Result := ''; 65 | end; 66 | 67 | function GetDescriptionAtAddr(AAddress: NativeUInt; ASymbols: TSymbols; 68 | AMap: TDebugMap): string; 69 | var 70 | LineNumber: Integer; 71 | AModuleName, AUnitName, AFuncName: string; 72 | BaseAddr: NativeUInt; 73 | begin 74 | LineNumber := AMap.GetLineNumberAtAddrForced(AAddress, 400, AUnitName); 75 | AModuleName := GetModuleNameFromAddr(BaseAddr); 76 | AFuncName := AMap.GetDescriptionAtAddrWithOffset(AAddress, AModuleName); 77 | if LineNumber <= 0 then 78 | begin 79 | BaseAddr := GetBaseAddr(AAddress); 80 | Result := ASymbols.GetDescriptionAtAddr(AAddress, BaseAddr, AModuleName); 81 | Result := Format('%.8x: %s', [AAddress, Result]); 82 | end 83 | else 84 | begin 85 | if AFuncName <> '' then 86 | AUnitName := ''; 87 | AFuncName := AUnitName + GetFunction(AFuncName); 88 | Result := Format('%.8x: %s line %d', [AAddress, AFuncName, LineNumber]); 89 | end; 90 | end; 91 | 92 | procedure InitMap(Map: TDebugMap); 93 | const 94 | LIST_MODULES_ALL = 3; 95 | var 96 | Buff: array of THandle; 97 | Needed: DWORD; 98 | I: Integer; 99 | FileNameBuff: array[0..MAX_PATH] of Char; 100 | FileName: string; 101 | begin 102 | EnumProcessModulesEx(GetCurrentProcess, nil, 0, Needed, LIST_MODULES_ALL); 103 | SetLength(Buff, Needed shr 2); 104 | if EnumProcessModulesEx(GetCurrentProcess, @Buff[0], Needed, Needed, LIST_MODULES_ALL) then 105 | begin 106 | for I := 0 to Integer(Needed) - 1 do 107 | if Buff[I] <> 0 then 108 | begin 109 | FillChar(FileNameBuff, MAX_PATH, 0); 110 | GetModuleFileNameEx(GetCurrentProcess, Buff[I], @FileNameBuff[0], MAX_PATH); 111 | FileName := string(PChar(@FileNameBuff[0])); 112 | if FileExists(ChangeFileExt(FileName, '.map')) then 113 | Map.Init(Buff[I], FileName); 114 | end; 115 | end; 116 | end; 117 | 118 | function GetCallStack(FramesCount: Integer): TStringList; 119 | var 120 | Map: TDebugMap; 121 | Symbols: TSymbols; 122 | Stack: array of NativeUInt; 123 | I: Integer; 124 | begin 125 | Result := TStringList.Create; 126 | try 127 | if FramesCount <= 0 then 128 | Exit; 129 | Map := TDebugMap.Create; 130 | try 131 | Map.LoadLines := True; 132 | InitMap(Map); 133 | Symbols := TSymbols.Create(GetCurrentProcess); 134 | try 135 | SetLength(Stack, FramesCount); 136 | for I := 1 to RtlCaptureStackBackTrace(0, FramesCount, @Stack[0], nil) - 1 do 137 | Result.Add(GetDescriptionAtAddr(Stack[I], Symbols, Map)); 138 | finally 139 | Symbols.Free; 140 | end; 141 | finally 142 | Map.Free; 143 | end; 144 | except 145 | FreeAndNil(Result); 146 | raise; 147 | end; 148 | end; 149 | 150 | end. 151 | -------------------------------------------------------------------------------- /MemoryMap/demos/CallStackCapture/README.md: -------------------------------------------------------------------------------- 1 | Call Stack Capture 2 | =================== 3 | 4 | Демонстрация работы с классами TSymbols и TDebugMap на примере снятия стека вызовов текущего приложения. 5 | 6 | ### Примерный результат работы: 7 | 8 | ![1](https://github.com/AlexanderBagel/ProcessMemoryMap/blob/master/MemoryMap/demos/CallStackCapture/img/callstackcapture.png?raw=true) 9 | -------------------------------------------------------------------------------- /MemoryMap/demos/CallStackCapture/Unit1.dfm: -------------------------------------------------------------------------------- 1 | object Form1: TForm1 2 | Left = 0 3 | Top = 0 4 | Caption = 'Form1' 5 | ClientHeight = 98 6 | ClientWidth = 177 7 | Color = clBtnFace 8 | Font.Charset = DEFAULT_CHARSET 9 | Font.Color = clWindowText 10 | Font.Height = -11 11 | Font.Name = 'Tahoma' 12 | Font.Style = [] 13 | OldCreateOrder = False 14 | OnCreate = FormCreate 15 | PixelsPerInch = 96 16 | TextHeight = 13 17 | object Button1: TButton 18 | Left = 8 19 | Top = 8 20 | Width = 145 21 | Height = 25 22 | Caption = 'Show CallStack' 23 | TabOrder = 0 24 | OnClick = Button1Click 25 | end 26 | object Button2: TButton 27 | Left = 8 28 | Top = 39 29 | Width = 145 30 | Height = 25 31 | Caption = 'Show Library CallStack' 32 | TabOrder = 1 33 | OnClick = Button2Click 34 | end 35 | end 36 | -------------------------------------------------------------------------------- /MemoryMap/demos/CallStackCapture/Unit1.pas: -------------------------------------------------------------------------------- 1 | unit Unit1; 2 | 3 | interface 4 | 5 | uses 6 | Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, 7 | Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls; 8 | 9 | type 10 | TShowCallStack = procedure; stdcall; 11 | 12 | TForm1 = class(TForm) 13 | Button1: TButton; 14 | Button2: TButton; 15 | procedure Button1Click(Sender: TObject); 16 | procedure FormCreate(Sender: TObject); 17 | procedure Button2Click(Sender: TObject); 18 | private 19 | LibShowCallStack: TShowCallStack; 20 | end; 21 | 22 | var 23 | Form1: TForm1; 24 | 25 | implementation 26 | 27 | uses 28 | CallStackTraceUtils; 29 | 30 | {$R *.dfm} 31 | 32 | procedure TForm1.Button1Click(Sender: TObject); 33 | var 34 | S: TStringList; 35 | begin 36 | S := GetCallStack; 37 | try 38 | ShowMessage(S.Text); 39 | finally 40 | S.Free; 41 | end; 42 | end; 43 | 44 | procedure TForm1.Button2Click(Sender: TObject); 45 | begin 46 | LibShowCallStack; 47 | end; 48 | 49 | procedure TForm1.FormCreate(Sender: TObject); 50 | var 51 | hLib: THandle; 52 | begin 53 | hLib := LoadLibrary('callstack_library.dll'); 54 | @LibShowCallStack := GetProcAddress(hLib, 'ShowCallStack'); 55 | Button2.Enabled := Assigned(LibShowCallStack); 56 | end; 57 | 58 | end. 59 | -------------------------------------------------------------------------------- /MemoryMap/demos/CallStackCapture/callstack_library.dpr: -------------------------------------------------------------------------------- 1 | library callstack_library; 2 | 3 | { Important note about DLL memory management: ShareMem must be the 4 | first unit in your library's USES clause AND your project's (select 5 | Project-View Source) USES clause if your DLL exports any procedures or 6 | functions that pass strings as parameters or function results. This 7 | applies to all strings passed to and from your DLL--even those that 8 | are nested in records and classes. ShareMem is the interface unit to 9 | the BORLNDMM.DLL shared memory manager, which must be deployed along 10 | with your DLL. To avoid using BORLNDMM.DLL, pass string information 11 | using PChar or ShortString parameters. } 12 | 13 | uses 14 | Windows, 15 | System.SysUtils, 16 | System.Classes, 17 | CallStackTraceUtils in 'CallStackTraceUtils.pas', 18 | MemoryMap.DebugMapData in '..\..\MemoryMap.DebugMapData.pas', 19 | MemoryMap.ImageHlp in '..\..\MemoryMap.ImageHlp.pas', 20 | MemoryMap.NtDll in '..\..\MemoryMap.NtDll.pas', 21 | MemoryMap.PEImage in '..\..\MemoryMap.PEImage.pas', 22 | MemoryMap.Symbols in '..\..\MemoryMap.Symbols.pas', 23 | MemoryMap.Utils in '..\..\MemoryMap.Utils.pas'; 24 | 25 | {$R *.res} 26 | 27 | procedure InternalShowCallStack; 28 | var 29 | S: TStringList; 30 | begin 31 | S := GetCallStack; 32 | try 33 | MessageBox(0, PChar(S.Text), '', MB_ICONINFORMATION); 34 | finally 35 | S.Free; 36 | end; 37 | end; 38 | 39 | procedure ShowCallStack; stdcall; 40 | begin 41 | InternalShowCallStack; 42 | end; 43 | 44 | exports 45 | ShowCallStack; 46 | 47 | begin 48 | end. 49 | -------------------------------------------------------------------------------- /MemoryMap/demos/CallStackCapture/img/callstackcapture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexanderBagel/ProcessMemoryMap/c5dc46ff63fb0fa20f6728abed0214786f91e4a2/MemoryMap/demos/CallStackCapture/img/callstackcapture.png -------------------------------------------------------------------------------- /MemoryMap/demos/CallStackConverter/CallStackConverter.dpr: -------------------------------------------------------------------------------- 1 | program CallStackConverter; 2 | 3 | uses 4 | Vcl.Forms, 5 | Unit1 in 'Unit1.pas' {dlgStackConverter}, 6 | MemoryMap.DebugMapData in '..\..\MemoryMap.DebugMapData.pas', 7 | MemoryMap.ImageHlp in '..\..\MemoryMap.ImageHlp.pas', 8 | MemoryMap.NtDll in '..\..\MemoryMap.NtDll.pas', 9 | MemoryMap.PEImage in '..\..\MemoryMap.PEImage.pas', 10 | MemoryMap.Utils in '..\..\MemoryMap.Utils.pas'; 11 | 12 | {$R *.res} 13 | 14 | begin 15 | Application.Initialize; 16 | Application.MainFormOnTaskbar := True; 17 | Application.CreateForm(TdlgStackConverter, dlgStackConverter); 18 | Application.Run; 19 | end. 20 | -------------------------------------------------------------------------------- /MemoryMap/demos/CallStackConverter/README.md: -------------------------------------------------------------------------------- 1 | Call Stack Converter 2 | ================ 3 | 4 | Демонстрация работы с классом TDebugMap на примере конвертации стека вызовов снятого при помощи Process Explorer https://learn.microsoft.com/en-us/sysinternals/downloads/process-explorer 5 | 6 | ### Внешний вид: 7 | 8 | ![1](https://github.com/AlexanderBagel/ProcessMemoryMap/blob/master/MemoryMap/demos/CallStackConverter/img/1.png?raw=true "Внешний вид") 9 | 10 | ### Принцип работы 11 | 12 | 1. Выбрать в Process Explorer требуемый процесс. 13 | 2. Перейти в свойства процесса на вкладку Threads, вызвать Stack интересующего потока. 14 | 3. Скопировать выведеный стек в буфер обмена. 15 | 16 | ![2](https://github.com/AlexanderBagel/ProcessMemoryMap/blob/master/MemoryMap/demos/CallStackConverter/img/2.png?raw=true ) 17 | 18 | * В утилите установить ImageBase исполняемого файла (или библиотеки - смотря что интересует) 19 | * Открыть исполняемый файл или библиотеку (наличие MAP файла обязательно) 20 | * Нажать кнопку конвертации 21 | * Результат можно скопировать через PopupMenu -------------------------------------------------------------------------------- /MemoryMap/demos/CallStackConverter/Unit1.dfm: -------------------------------------------------------------------------------- 1 | object dlgStackConverter: TdlgStackConverter 2 | Left = 0 3 | Top = 0 4 | Caption = 'Sysinternals Process Explorer Call Stack Converter' 5 | ClientHeight = 588 6 | ClientWidth = 1225 7 | Color = clBtnFace 8 | Font.Charset = DEFAULT_CHARSET 9 | Font.Color = clWindowText 10 | Font.Height = -11 11 | Font.Name = 'Tahoma' 12 | Font.Style = [] 13 | OldCreateOrder = False 14 | Position = poScreenCenter 15 | OnCreate = FormCreate 16 | OnDestroy = FormDestroy 17 | PixelsPerInch = 96 18 | TextHeight = 13 19 | object pnTop: TPanel 20 | Left = 0 21 | Top = 0 22 | Width = 1225 23 | Height = 553 24 | Align = alClient 25 | BevelOuter = bvNone 26 | TabOrder = 0 27 | object Splitter: TSplitter 28 | Left = 385 29 | Top = 0 30 | Width = 6 31 | Height = 553 32 | Color = clBtnShadow 33 | ParentColor = False 34 | ExplicitLeft = 431 35 | ExplicitHeight = 551 36 | end 37 | object memStack: TMemo 38 | Left = 0 39 | Top = 0 40 | Width = 385 41 | Height = 553 42 | Align = alLeft 43 | DoubleBuffered = True 44 | ParentDoubleBuffered = False 45 | PopupMenu = memPopupMenu 46 | ScrollBars = ssBoth 47 | TabOrder = 0 48 | end 49 | object lvStack: TListView 50 | Left = 391 51 | Top = 0 52 | Width = 834 53 | Height = 553 54 | Align = alClient 55 | Columns = < 56 | item 57 | Caption = 'Address' 58 | Width = 128 59 | end 60 | item 61 | Caption = 'Module' 62 | Width = 150 63 | end 64 | item 65 | Caption = 'Unit' 66 | Width = 135 67 | end 68 | item 69 | Caption = 'Function' 70 | Width = 330 71 | end 72 | item 73 | Caption = 'Line' 74 | end> 75 | DoubleBuffered = True 76 | RowSelect = True 77 | ParentDoubleBuffered = False 78 | ParentShowHint = False 79 | PopupMenu = lvPopupMenu 80 | ShowHint = True 81 | TabOrder = 1 82 | ViewStyle = vsReport 83 | OnCustomDrawItem = lvStackCustomDrawItem 84 | OnInfoTip = lvStackInfoTip 85 | end 86 | object pnPaste: TPanel 87 | Left = 32 88 | Top = 96 89 | Width = 297 90 | Height = 41 91 | Caption = 'Paste CallStack Here!' 92 | TabOrder = 2 93 | object btnPaste: TButton 94 | Left = 208 95 | Top = 8 96 | Width = 75 97 | Height = 25 98 | Action = acPaste 99 | TabOrder = 0 100 | end 101 | end 102 | end 103 | object pnBottom: TPanel 104 | Left = 0 105 | Top = 553 106 | Width = 1225 107 | Height = 35 108 | Align = alBottom 109 | BevelOuter = bvNone 110 | TabOrder = 1 111 | object btnOpen: TButton 112 | Left = 279 113 | Top = 6 114 | Width = 75 115 | Height = 25 116 | Caption = 'Open File...' 117 | TabOrder = 0 118 | OnClick = btnOpenClick 119 | end 120 | object btnConvert: TButton 121 | Left = 360 122 | Top = 6 123 | Width = 97 124 | Height = 25 125 | Action = acConvert 126 | TabOrder = 1 127 | end 128 | object edBase: TLabeledEdit 129 | Left = 152 130 | Top = 8 131 | Width = 121 132 | Height = 21 133 | EditLabel.Width = 132 134 | EditLabel.Height = 13 135 | EditLabel.Caption = 'Image Base Address (HEX):' 136 | LabelPosition = lpLeft 137 | TabOrder = 2 138 | Text = '400000' 139 | OnChange = edBaseChange 140 | end 141 | end 142 | object OpenDialog: TOpenDialog 143 | Filter = 144 | 'Executable file (*.exe)|*.exe|Library (*.dll)|*.dll|All Files (*' + 145 | '.*)|*.*' 146 | Left = 448 147 | Top = 80 148 | end 149 | object lvPopupMenu: TPopupMenu 150 | Left = 520 151 | Top = 80 152 | object acCopyAddr1: TMenuItem 153 | Action = acCopyAddr 154 | end 155 | object acCopyLine1: TMenuItem 156 | Action = acCopyLine 157 | end 158 | object N1: TMenuItem 159 | Caption = '-' 160 | end 161 | object acCopyAll1: TMenuItem 162 | Action = acCopyAll 163 | end 164 | end 165 | object ActionList: TActionList 166 | Left = 608 167 | Top = 80 168 | object acPaste: TAction 169 | Caption = 'Paste' 170 | OnExecute = acPasteExecute 171 | OnUpdate = acPasteUpdate 172 | end 173 | object acConvert: TAction 174 | Caption = 'Convert >>>' 175 | OnExecute = acConvertExecute 176 | OnUpdate = acConvertUpdate 177 | end 178 | object acCopyAddr: TAction 179 | Caption = 'acCopyAddr' 180 | OnExecute = acCopyAddrExecute 181 | OnUpdate = acCopyAddrUpdate 182 | end 183 | object acCopyLine: TAction 184 | Caption = 'acCopyLine' 185 | OnExecute = acCopyLineExecute 186 | OnUpdate = acCopyLineUpdate 187 | end 188 | object acCopyAll: TAction 189 | Caption = 'acCopyAll' 190 | OnExecute = acCopyAllExecute 191 | OnUpdate = acCopyAllUpdate 192 | end 193 | end 194 | object memPopupMenu: TPopupMenu 195 | Left = 520 196 | Top = 136 197 | object PasteCollStack1: TMenuItem 198 | Action = acPaste 199 | end 200 | end 201 | end 202 | -------------------------------------------------------------------------------- /MemoryMap/demos/CallStackConverter/img/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexanderBagel/ProcessMemoryMap/c5dc46ff63fb0fa20f6728abed0214786f91e4a2/MemoryMap/demos/CallStackConverter/img/1.png -------------------------------------------------------------------------------- /MemoryMap/demos/CallStackConverter/img/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexanderBagel/ProcessMemoryMap/c5dc46ff63fb0fa20f6728abed0214786f91e4a2/MemoryMap/demos/CallStackConverter/img/2.png -------------------------------------------------------------------------------- /ProcessMM.dpr: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // **************************************************************************** 4 | // * Project : ProcessMM 5 | // * Unit Name : ProcessMM.dpr 6 | // * Author : Александр (Rouse_) Багель 7 | // * Copyright : © Fangorn Wizards Lab 1998 - 2022. 8 | // * Version : 1.0.14 9 | // * Home Page : http://rouse.drkb.ru 10 | // * Home Blog : http://alexander-bagel.blogspot.ru 11 | // **************************************************************************** 12 | // * Stable Release : http://rouse.drkb.ru/winapi.php#pmm2 13 | // * Latest Source : https://github.com/AlexanderBagel/ProcessMemoryMap 14 | // **************************************************************************** 15 | // 16 | 17 | program ProcessMM; 18 | 19 | uses 20 | Winapi.Windows, 21 | Winapi.Messages, 22 | Vcl.Forms, 23 | System.SysUtils, 24 | uProcessMM in 'src\gui\uProcessMM.pas' {dlgProcessMM}, 25 | uSelectProcess in 'src\gui\uSelectProcess.pas' {dlgSelectProcess}, 26 | uExportList in 'src\gui\uExportList.pas' {dlgExportList}, 27 | uSettings in 'src\gui\uSettings.pas' {dlgSettings}, 28 | uUtils in 'src\uUtils.pas', 29 | uDisplayUtils in 'src\uDisplayUtils.pas', 30 | uRegionProperties in 'src\gui\uRegionProperties.pas' {dlgRegionProps}, 31 | uSelectAddress in 'src\gui\uSelectAddress.pas' {dlgSelectAddress}, 32 | uFindData in 'src\gui\uFindData.pas' {dlgFindData}, 33 | uComparator in 'src\gui\uComparator.pas' {dlgComparator}, 34 | uProgress in 'src\gui\uProgress.pas' {dlgProgress}, 35 | uDump in 'src\uDump.pas', 36 | uDumpDisplayUtils in 'src\uDumpDisplayUtils.pas', 37 | uIPC in 'src\uIPC.pas', 38 | MemoryMap.Core in 'MemoryMap\MemoryMap.Core.pas', 39 | MemoryMap.Heaps in 'MemoryMap\MemoryMap.Heaps.pas', 40 | MemoryMap.NtDll in 'MemoryMap\MemoryMap.NtDll.pas', 41 | MemoryMap.PEImage in 'MemoryMap\MemoryMap.PEImage.pas', 42 | MemoryMap.RegionData in 'MemoryMap\MemoryMap.RegionData.pas', 43 | MemoryMap.Symbols in 'MemoryMap\MemoryMap.Symbols.pas', 44 | MemoryMap.Threads in 'MemoryMap\MemoryMap.Threads.pas', 45 | MemoryMap.Utils in 'MemoryMap\MemoryMap.Utils.pas', 46 | MemoryMap.Workset in 'MemoryMap\MemoryMap.Workset.pas', 47 | uAbout in 'src\gui\uAbout.pas' {dlgAbout}, 48 | uMemoryMapListInfo in 'src\gui\uMemoryMapListInfo.pas' {dlgMemoryMapListInfo}, 49 | uMemoryMapListInfoSettings in 'src\gui\uMemoryMapListInfoSettings.pas' {dlgMemoryMapListInfoSettings}, 50 | distorm in 'distorm\distorm.pas', 51 | MemoryMap.DebugMapData in 'MemoryMap\MemoryMap.DebugMapData.pas', 52 | uProcessReconnect in 'src\uProcessReconnect.pas', 53 | MemoryMap.ImageHlp in 'MemoryMap\MemoryMap.ImageHlp.pas', 54 | mnemonics in 'distorm\mnemonics.pas', 55 | uKnownData in 'src\gui\uKnownData.pas' {dlgKnownData}, 56 | uPatchDetect in 'src\gui\uPatchDetect.pas' {dlgPatches}, 57 | RawScanner.Analyzer in 'RawScanner\RawScanner.Analyzer.pas', 58 | RawScanner.ApiSet in 'RawScanner\RawScanner.ApiSet.pas', 59 | RawScanner.Disassembler in 'RawScanner\RawScanner.Disassembler.pas', 60 | RawScanner.Filter in 'RawScanner\RawScanner.Filter.pas', 61 | RawScanner.LoaderData in 'RawScanner\RawScanner.LoaderData.pas', 62 | RawScanner.Logger in 'RawScanner\RawScanner.Logger.pas', 63 | RawScanner.Image.Pe in 'RawScanner\RawScanner.Image.Pe.pas', 64 | RawScanner.Types in 'RawScanner\RawScanner.Types.pas', 65 | RawScanner.Utils in 'RawScanner\RawScanner.Utils.pas', 66 | RawScanner.Wow64 in 'RawScanner\RawScanner.Wow64.pas', 67 | RawScanner.Core in 'RawScanner\RawScanner.Core.pas', 68 | RawScanner.SymbolStorage in 'RawScanner\RawScanner.SymbolStorage.pas', 69 | RawScanner.ActivationContext in 'RawScanner\RawScanner.ActivationContext.pas', 70 | FWProgressBar in 'Controls\FWProgressBar.pas', 71 | pmm_plugin in 'plugins\include\pmm_plugin.pas', 72 | uPluginManager in 'src\uPluginManager.pas', 73 | uDebugInfoDlg in 'src\gui\uDebugInfoDlg.pas' {dlgDbgInfo}, 74 | Shell.TaskBarListProgress in 'Controls\Shell.TaskBarListProgress.pas', 75 | RawScanner.X64Gates in 'RawScanner\RawScanner.X64Gates.pas', 76 | uStringsViewer in 'src\gui\uStringsViewer.pas' {dlgStringsViewer}, 77 | ScaledCtrls in 'Controls\ScaledCtrls.pas', 78 | uBaseForm in 'src\gui\uBaseForm.pas' {BaseAppForm}, 79 | RawScanner.CoffDwarf in 'RawScanner\RawScanner.CoffDwarf.pas', 80 | uCallStack in 'src\gui\uCallStack.pas' {dlgCallStack}, 81 | RawScanner.Elf in 'RawScanner\RawScanner.Elf.pas', 82 | RawScanner.Image.Elf in 'RawScanner\RawScanner.Image.Elf.pas', 83 | RawScanner.MapGenerator in 'RawScanner\RawScanner.MapGenerator.pas', 84 | RawScanner.AbstractImage in 'RawScanner\RawScanner.AbstractImage.pas', 85 | RawScanner.Image.Coff in 'RawScanner\RawScanner.Image.Coff.pas', 86 | uSearchResult in 'src\gui\uSearchResult.pas' {dlgSearchResult}; 87 | 88 | {$R *.res} 89 | 90 | // Директива SINGLE_INSTANCE не дает запускать 32 битному приложению 64 битный аналог 91 | // Сугубо для отладки 92 | {$IFDEF SINGLE_INSTANCE} 93 | begin 94 | Application.Initialize; 95 | Application.MainFormOnTaskbar := True; 96 | Application.CreateForm(TdlgProcessMM, dlgProcessMM); 97 | Application.Run; 98 | 99 | {$ELSE} 100 | 101 | {$IFDEF WIN32} 102 | 103 | {$IFDEF DEBUG} 104 | {$R 'win64debug.res' 'win64debug.rc'} 105 | {$ELSE} 106 | {$R 'win64release.res' 'win64release.rc'} 107 | {$ENDIF} 108 | 109 | var 110 | IPC: TIPCServer; 111 | New64AppHandle: THandle; 112 | Msg: TMsg; 113 | Path: string; 114 | {$ENDIF} // {$IFDEF WIN32} 115 | begin 116 | {$IFDEF WIN32} 117 | if Is64OS and not FindCmdLineSwitch('32', ['x'], True) then 118 | begin 119 | // Если OS 64-битная, то запускаем соответствующее приложение, 120 | // а сами остаемся висеть чтобы отдавать ему данные о 32-битных кучах. 121 | // Правда если 64-битное приложение перезапустится из под админа 122 | // то доступа к нему мы уже иметь не будем, придется закрываться. 123 | // Потом этот механизм пересмотрю как нибудь по нормальному. 124 | IPC := TIPCServer.Create; 125 | try 126 | Path := ExtractFilePath(ParamStr(0)) + 'processmm64.exe'; 127 | New64AppHandle := Run64App(Path, IPC.MMFName); 128 | if New64AppHandle <> 0 then 129 | try 130 | while WaitForSingleObject(New64AppHandle, 50) = WAIT_TIMEOUT do 131 | begin 132 | while PeekMessage(Msg, 0, 0, 0, PM_REMOVE) do 133 | begin 134 | TranslateMessage(Msg); 135 | DispatchMessage(Msg); 136 | end; 137 | end; 138 | finally 139 | CloseHandle(New64AppHandle); 140 | end; 141 | finally 142 | DeleteFile(Path); 143 | IPC.Free; 144 | end; 145 | if New64AppHandle <> 0 then Exit; 146 | end; 147 | {$ENDIF} // {$IFDEF WIN32} 148 | Application.Initialize; 149 | Application.MainFormOnTaskbar := True; 150 | Application.CreateForm(TdlgProcessMM, dlgProcessMM); 151 | Application.Run; 152 | {$ENDIF} // {$IFDEF SINGLE_INSTANCE} -> {$ELSE} 153 | end. 154 | -------------------------------------------------------------------------------- /ProcessMM.res: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexanderBagel/ProcessMemoryMap/c5dc46ff63fb0fa20f6728abed0214786f91e4a2/ProcessMM.res -------------------------------------------------------------------------------- /ProcessMM.stat: -------------------------------------------------------------------------------- 1 | [Stats] 2 | EditorSecs=16018 3 | DesignerSecs=784 4 | InspectorSecs=613 5 | CompileSecs=114678 6 | OtherSecs=1582 7 | StartTime=18.05.2016 13:15:59 8 | RealKeys=0 9 | EffectiveKeys=0 10 | DebugSecs=7713 11 | -------------------------------------------------------------------------------- /ProcessMM_Icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexanderBagel/ProcessMemoryMap/c5dc46ff63fb0fa20f6728abed0214786f91e4a2/ProcessMM_Icon.ico -------------------------------------------------------------------------------- /ProcessMM_Icon1.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexanderBagel/ProcessMemoryMap/c5dc46ff63fb0fa20f6728abed0214786f91e4a2/ProcessMM_Icon1.ico -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Process Memory Map 2 | ================ 3 | 4 | Утилита предназначена для отображения карты памяти процесса. 5 | 6 | ![1](https://github.com/AlexanderBagel/ProcessMemoryMap/blob/master/img/1.png?raw=true "Внешний вид") 7 | 8 | Отображает следующие данные: 9 | 10 | * кучи процесса 11 | * данные по нитям, как то: стек, TEB, SEH фреймы и CallStack 12 | * информация по подгруженным PE файлам с разбивкой на секции, точки входа в каждый загруженный образ, их структуры 13 | * данные из PEB 14 | * данные из KUSER_SHARED_DATA 15 | * встроенный x86/x64 дизассемблер (на базе DiStorm) 16 | 17 | Предоставляет возможность: 18 | * анализа памяти на предмет установленных перехватчиков в таблицах импорта/экспорта/отложенного импорта 19 | * анализа установленных перехватчиков в экспортируемых функциях, точках входа и TLS калбэках 20 | * анализа блоков памяти на основе их контрольных сумм (например отображение изменений во взломанном ПО). 21 | * поиска в памяти процесса. 22 | 23 | Из дополнительных возможностей: 24 | * выводит список экспортируемых функций. 25 | * поддерживает отладочные MAP файлы. (влияет на список распознанных функций и выхлоп дизассемблера) 26 | * отображает изменения в выделенных блоках памяти (alloc/realloc/free) 27 | * быстрая подсказка по известным блокам памяти 28 | 29 | ### Сборка проекта: 30 | 31 | Для самостоятельной сборки потребуется: 32 | 33 | * установленный пакет компонентов Virtual TreeView версии 8.0 и выше: https://github.com/JAM-Software/Virtual-TreeView 34 | * установленный набор классов для работы с ZIP архивами FWZip версии 1.0.9 и выше: https://github.com/AlexanderBagel/FWZip 35 | 36 | Сборка осуществляется с использованием Delphi 10.4.2 Sydney в режиме "Win32/Release", при этом автоматически будет собрана и подключена (в виде ресурса) 64-битная версия данной утилиты. 37 | Под более старыми версиями Delphi работоспособность ProcessMemoryMap не проверялась и не гарантируется. 38 | 39 | ### Внутренние версии фреймворков: 40 | * MemoryMap Core - 1.4.37 41 | * RawScanner Core - 1.1.25 42 | * FWZip - 2.0.6 43 | * Distorm - 3.5.3 44 | 45 | ### RoadMap (с предположительными версиями): 46 | 47 | * 1.5 полная поддержка DWARF 4 и 5 версий, поддержка типов STUB 48 | * 1.6 вывод размапленой информации по директории resources 49 | * 1.6 вывод используемых ресурсов в виде дерева 50 | * 1.7 вывод размапленой информации по директорям exceptions, security 51 | * 1.7 вывод размапленой информации по директории com+ в виде дерева 52 | * 1.8 вывод размапленой информации по директории debug 53 | * 1.8 поддержка отладочных PDB файлов 54 | * 1.8 перевод вывода системных структур на основе полученных данных из PDB 55 | * 1.9 поддержка отладочной информации JclDebug (возможно в виде плагина) 56 | * 2.0 перевод Hex дампов и дизассемблера на FWHexView 57 | 58 | ### Обновления: 59 | 60 | 1.5.46 от 28.02.2025 61 | * Исправлена ошибка "Division by zero." при чтении DWARF у исполняемых файлов с малым обьемом отладочной информации. 62 | 63 | 1.5.45 от 10.11.2024 64 | * В анализаторе хуков расширен warning при проверке ImgDelayDescr.ModuleInstance. Добавлена информация об адресе дескриптора. 65 | * В свойствах региона ImgDelayDescr.ModuleInstance теперь дополнительно выводит адрес и имя модуля. 66 | * Изменен диалог поиска, предыдущие поисковые запросы сохраняются в течении сессии. 67 | * Новый диалог результатов поиска. 68 | * В настройки добавлен лимит выводимых поисковых запросов (максимум 1000). 69 | * Исправлена неверная работа с флагом PAGE_WRITECOPY при чтении 70 | * Исправлена неверная работа якорей при смене DPI у нижнего вьювера страниц на главной форме. 71 | 72 | 1.5.44 от 07.11.2024 73 | * В настройки добавлен таймер автообновления окна свойств региона. По умолчанию отключен. 74 | 75 | 1.5.43 от 30.10.2024 76 | * Исправлен некорректный контроль результата в GetDwarfLineAtAddr, приводящий к "Argument out of range". 77 | 78 | Полный список обновлений в файле updates.txt 79 | 80 | ### Скриншоты: 81 | 82 | Как и в оригинальной утилите от Марка Руссиновича, присутствует фильтрация по типам данных. 83 | В данном случае отображаются только те блоки памяти, которые содержат системные данные (KUSER_SHARED_DATA, PEB, etc...) 84 | 85 | ![2](https://github.com/AlexanderBagel/ProcessMemoryMap/blob/master/img/2.png?raw=true "Фильтрация") 86 | 87 | Данные всех поддерживаемых структур размаплены для их более удобного восприятия. 88 | К примеру, вот так выглядит отображение блока окружения 64 битного процесса. 89 | 90 | ![3](https://github.com/AlexanderBagel/ProcessMemoryMap/blob/master/img/3.png?raw=true "PEB") 91 | 92 | А вот так выглядит IMAGE_DOS_HEADER 93 | 94 | ![4](https://github.com/AlexanderBagel/ProcessMemoryMap/blob/master/img/4.png?raw=true "IMAGE_DOS_HEADER") 95 | 96 | Если не известно что за структура мапится на текущий адрес памяти, то данные отобрадаются в RAW режиме. 97 | Например вот так выглядит код на точке входа kernel32.dll 98 | 99 | ![5.1](https://github.com/AlexanderBagel/ProcessMemoryMap/blob/master/img/5.png?raw=true "Entry Point RAW") 100 | 101 | Он же, но в виде дизассемблированного кода (переключение между видами в меню по правой клавише мышки "Show as disassembly" или по горячей клавише Ctrl+D): 102 | 103 | ![5.2](https://github.com/AlexanderBagel/ProcessMemoryMap/blob/master/img/6.png?raw=true "Entry Point Disassembled") 104 | 105 | * Для нагрядности дизассемблерный выхлоп форматирован. 106 | * Код известных экспортируемых функций предваряется описанием. 107 | * Выхлоп форматируется дабы не мозолили глаза NOP и INT3 инструкции, выделяется окончание функций (RET/IRET/RETF). 108 | 109 | ![5.3](https://github.com/AlexanderBagel/ProcessMemoryMap/blob/master/img/9.png?raw=true "NTDLL Export") 110 | 111 | Для быстрой навигации по известным структурам предсмотрено оглавление, доступное через меню View -> Show Known Data... или по горячей клавише F2 112 | 113 | ![6](https://github.com/AlexanderBagel/ProcessMemoryMap/blob/master/img/12.png?raw=true "Known Data") 114 | 115 | Присутствует список всех импортируемых/экспортируемых функций (Ctrl+E). 116 | В него же добавляются данные из отладочного МАР файла (если присутствует - поддерживаются MAP файлы Delphi/С++) 117 | К нему добавлен поиск как по адресу, так и по имени функции (поиск по наименованию библиотеки не производится) 118 | 119 | ![7](https://github.com/AlexanderBagel/ProcessMemoryMap/blob/master/img/7.png?raw=true "Export list") 120 | 121 | При наличии информации известные вызовы в дизассемблере коментируются. 122 | ![7.1](https://github.com/AlexanderBagel/ProcessMemoryMap/blob/master/img/10.png?raw=true "CALL hint") 123 | 124 | Включая вызовы через таблицу импорта. 125 | ![7.2](https://github.com/AlexanderBagel/ProcessMemoryMap/blob/master/img/11.png?raw=true "CALL import hint") 126 | 127 | Присутствует модуль анализа процесса на предмет установленых перехватчиков фунций (F8) 128 | ![8](https://github.com/AlexanderBagel/ProcessMemoryMap/blob/master/img/14.png?raw=true "Hook scanner output") 129 | 130 | Присутствует модуль деманглинга стека вызовов потоков включая 32 и 64 бита + 32SEH (F4) 131 | ![9](https://github.com/AlexanderBagel/ProcessMemoryMap/blob/master/img/15.png?raw=true "Threads CallStack") 132 | 133 | Результаты поиска выводятся в отдельный диалог (Shift+F) 134 | ![10](https://github.com/AlexanderBagel/ProcessMemoryMap/blob/master/img/16.png?raw=true "Search Results") 135 | 136 | Ну и вот так выглядит список изменений в выделенных блоках с последней проверки (F5) 137 | 138 | ![11](https://github.com/AlexanderBagel/ProcessMemoryMap/blob/master/img/8.png?raw=true "Compare result") 139 | 140 | Ну и много много чего еще интересного. -------------------------------------------------------------------------------- /RawScanner/RawScanner.AbstractImage.pas: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // **************************************************************************** 4 | // * Project : ProcessMM 5 | // * Unit Name : RawScanner.AbstractImage.pas 6 | // * Purpose : Базовый класс образа файла с которым умеет работать RawScanner 7 | // * Author : Александр (Rouse_) Багель 8 | // * Copyright : © Fangorn Wizards Lab 1998 - 2024. 9 | // * Version : 1.1.24 10 | // * Home Page : http://rouse.drkb.ru 11 | // * Home Blog : http://alexander-bagel.blogspot.ru 12 | // **************************************************************************** 13 | // * Stable Release : http://rouse.drkb.ru/winapi.php#pmm2 14 | // * Latest Source : https://github.com/AlexanderBagel/ProcessMemoryMap 15 | // **************************************************************************** 16 | // 17 | 18 | unit RawScanner.AbstractImage; 19 | 20 | interface 21 | 22 | {$I rawscanner.inc} 23 | 24 | uses 25 | Windows, 26 | {$IFDEF USE_PROFILING} 27 | Diagnostics, 28 | {$ENDIF} 29 | RawScanner.Types, 30 | RawScanner.CoffDwarf; 31 | 32 | type 33 | TSectionData = record 34 | Index: Integer; 35 | StartRVA, Size: DWORD; 36 | Read, Write, Execute: Boolean; 37 | end; 38 | 39 | TImageType = (itUnknown, 40 | itPE32, itPE64, itELF32, itELF64, itCOFF32, itCOFF64, 41 | // OMF пока что не поддерживается, т.к. не понятно где его взять с DWARF отладочными 42 | itOMF32, itOMF64); 43 | 44 | TAbstractImage = class 45 | public class var 46 | DefaultDwarfAppendUnitName: Boolean; 47 | private 48 | FImageType: TImageType; 49 | FElapsed: Int64; 50 | {$IFDEF USE_PROFILING} 51 | FStopwatch: TStopwatch; 52 | {$ENDIF} 53 | protected 54 | function AlignDown(Value: DWORD; Align: DWORD): DWORD; 55 | function AlignUp(Value: DWORD; Align: DWORD): DWORD; 56 | procedure ProfilingBegin; 57 | procedure ProfilingEnd; 58 | procedure SetImageType(Value: TImageType); 59 | public 60 | function DebugData: TDebugInfoTypes; virtual; abstract; 61 | function DebugLinkPath: string; virtual; abstract; 62 | function DwarfDebugInfo: TDwarfDebugInfo; virtual; abstract; 63 | property Elapsed: Int64 read FElapsed; 64 | function GetSectionData(RvaAddr: DWORD; var Data: TSectionData): Boolean; virtual; abstract; 65 | function Image64: Boolean; virtual; abstract; 66 | function ImageBase: ULONG_PTR64; virtual; abstract; 67 | function RawToVa(RawAddr: DWORD): ULONG_PTR64; virtual; abstract; 68 | function VaToRaw(AddrVA: ULONG_PTR64): DWORD; virtual; abstract; 69 | function VaToRva(VaAddr: ULONG_PTR64): DWORD; virtual; abstract; 70 | property ImageType: TImageType read FImageType; 71 | end; 72 | 73 | implementation 74 | 75 | { TAbstractImage } 76 | 77 | function TAbstractImage.AlignDown(Value, Align: DWORD): DWORD; 78 | begin 79 | Result := Value and not DWORD(Align - 1); 80 | end; 81 | 82 | function TAbstractImage.AlignUp(Value, Align: DWORD): DWORD; 83 | begin 84 | if Value = 0 then Exit(0); 85 | Result := AlignDown(Value - 1, Align) + Align; 86 | end; 87 | 88 | procedure TAbstractImage.ProfilingBegin; 89 | begin 90 | {$IFDEF USE_PROFILING} 91 | FStopwatch := TStopwatch.StartNew; 92 | {$ENDIF} 93 | end; 94 | 95 | procedure TAbstractImage.ProfilingEnd; 96 | begin 97 | {$IFDEF USE_PROFILING} 98 | FElapsed := FStopwatch.ElapsedMilliseconds; 99 | {$ENDIF} 100 | end; 101 | 102 | procedure TAbstractImage.SetImageType(Value: TImageType); 103 | begin 104 | FImageType := Value; 105 | end; 106 | 107 | end. 108 | -------------------------------------------------------------------------------- /RawScanner/RawScanner.Filter.pas: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // **************************************************************************** 4 | // * Project : ProcessMM 5 | // * Unit Name : RawScanner.Filter.pas 6 | // * Purpose : Класс для быстрой фильтрации результатов анализатора. 7 | // * : Не используется в составе фреймворка, 8 | // * : и предназначен для внешнего кода. 9 | // * Author : Александр (Rouse_) Багель 10 | // * Copyright : © Fangorn Wizards Lab 1998 - 2023. 11 | // * Version : 1.0.11 12 | // * Home Page : http://rouse.drkb.ru 13 | // * Home Blog : http://alexander-bagel.blogspot.ru 14 | // **************************************************************************** 15 | // * Stable Release : http://rouse.drkb.ru/winapi.php#pmm2 16 | // * Latest Source : https://github.com/AlexanderBagel/ProcessMemoryMap 17 | // **************************************************************************** 18 | // 19 | 20 | unit RawScanner.Filter; 21 | 22 | interface 23 | 24 | {$I rawscanner.inc} 25 | 26 | uses 27 | Classes, 28 | SysUtils, 29 | Generics.Collections, 30 | RawScanner.Types; 31 | 32 | const 33 | FilterAll = '*'; 34 | AllHookTypes = [htImport..htCode]; 35 | ArrowMarker = ' -> '; 36 | 37 | type 38 | TFilterStatus = (fsNone, fsIgnore, fsCheck); 39 | TFilter = class 40 | private type 41 | TFilterData = record 42 | HookType: THookTypes; 43 | FilterStatus: TFilterStatus; 44 | end; 45 | private 46 | FData: TObjectDictionary>; 47 | FCheckList: TStringList; 48 | procedure InitDefaults; 49 | function CheckFuncTemplate(const Value: string): string; 50 | public 51 | constructor Create; 52 | destructor Destroy; override; 53 | /// 54 | /// Добавление фильтра в список 55 | /// HookHandler - библиотека в которую идет перенаправление 56 | /// FuncTemplate - имя функции в формате "библиотека.имя" 57 | /// на которой обнаружден перехватчик (например ntdll.RtlExitUserThread) 58 | /// HookTypes - расположение установленого перехвата 59 | /// FilterStatus - какой результат должен вернуть фильтр 60 | /// 61 | procedure AddFilter(HookHandler, FuncTemplate: string; 62 | HookTypes: THookTypes; FilterStatus: TFilterStatus); 63 | /// 64 | /// Проверка фильтра 65 | /// HookHandler - библиотека в которую идет перенаправление 66 | /// FuncTemplate - имя функции "библиотека.имя" которую перенаправили 67 | /// HookType - ресположение установленого перехвата 68 | /// 69 | function Check(HookHandler, FuncTemplate: string; 70 | HookType: THookType): TFilterStatus; 71 | procedure Clear; 72 | procedure CheckReset; 73 | function GetUncheckedCount: Integer; 74 | function GetUncheckedList: TStringList; 75 | end; 76 | 77 | implementation 78 | 79 | { TFilter } 80 | 81 | procedure TFilter.AddFilter(HookHandler, FuncTemplate: string; 82 | HookTypes: THookTypes; FilterStatus: TFilterStatus); 83 | var 84 | LibraryData: TDictionary; 85 | FilterData: TFilterData; 86 | begin 87 | HookHandler := LowerCase(HookHandler); 88 | FuncTemplate := CheckFuncTemplate(FuncTemplate); 89 | if not FData.TryGetValue(HookHandler, LibraryData) then 90 | begin 91 | LibraryData := TDictionary.Create; 92 | FData.Add(HookHandler, LibraryData); 93 | end; 94 | FilterData.HookType := HookTypes; 95 | FilterData.FilterStatus := FilterStatus; 96 | LibraryData.AddOrSetValue(FuncTemplate, FilterData); 97 | if FilterStatus = fsCheck then 98 | FCheckList.Add(FuncTemplate + ArrowMarker + HookHandler); 99 | end; 100 | 101 | function TFilter.Check(HookHandler, FuncTemplate: string; 102 | HookType: THookType): TFilterStatus; 103 | var 104 | LibraryData: TDictionary; 105 | FilterData: TFilterData; 106 | Index: Integer; 107 | begin 108 | Result := fsNone; 109 | HookHandler := LowerCase(HookHandler); 110 | FuncTemplate := CheckFuncTemplate(FuncTemplate); 111 | if FData.TryGetValue(HookHandler, LibraryData) then 112 | begin 113 | try 114 | // проверка конкретного фильтра на библиотека + имя 115 | // например ntdll.RtlExitUserThread 116 | if LibraryData.TryGetValue(FuncTemplate, FilterData) then 117 | begin 118 | if HookType in FilterData.HookType then 119 | Result := FilterData.FilterStatus; 120 | Exit; 121 | end; 122 | // проверка фильтра на библиотеку + любая функция 123 | // например ntdll.* 124 | Index := LastDelimiter('.', FuncTemplate); 125 | if Index > 0 then 126 | begin 127 | FuncTemplate := Copy(FuncTemplate, 1, Index) + FilterAll; 128 | if LibraryData.TryGetValue(FuncTemplate, FilterData) then 129 | begin 130 | if HookType in FilterData.HookType then 131 | Result := FilterData.FilterStatus; 132 | Exit; 133 | end; 134 | end; 135 | // проверка фильтра на хэндлер хука 136 | // например * 137 | if LibraryData.TryGetValue(FilterAll, FilterData) then 138 | begin 139 | if HookType in FilterData.HookType then 140 | Result := FilterData.FilterStatus; 141 | Exit; 142 | end; 143 | finally 144 | if Result = fsCheck then 145 | begin 146 | Index := FCheckList.IndexOf(FuncTemplate + ArrowMarker + HookHandler); 147 | if Index >= 0 then 148 | FCheckList.Objects[Index] := Pointer(1); 149 | end; 150 | end; 151 | end; 152 | end; 153 | 154 | function TFilter.CheckFuncTemplate(const Value: string): string; 155 | var 156 | Index: Integer; 157 | begin 158 | Index := LastDelimiter('.', Value); 159 | if Index > 0 then 160 | Result := Copy(Value, 1, Index).ToLower + 161 | Copy(Value, Index + 1, Length(Value)) 162 | else 163 | Result := Value; 164 | end; 165 | 166 | procedure TFilter.CheckReset; 167 | begin 168 | for var I := 0 to FCheckList.Count - 1 do 169 | FCheckList.Objects[I] := nil; 170 | end; 171 | 172 | procedure TFilter.Clear; 173 | begin 174 | FData.Clear; 175 | FCheckList.Clear; 176 | end; 177 | 178 | constructor TFilter.Create; 179 | begin 180 | FData := TObjectDictionary>.Create([doOwnsValues]); 182 | FCheckList := TStringList.Create; 183 | InitDefaults; 184 | end; 185 | 186 | destructor TFilter.Destroy; 187 | begin 188 | FCheckList.Free; 189 | FData.Free; 190 | inherited; 191 | end; 192 | 193 | function TFilter.GetUncheckedCount: Integer; 194 | begin 195 | Result := 0; 196 | for var I := 0 to FCheckList.Count - 1 do 197 | if FCheckList.Objects[I] = nil then 198 | Inc(Result); 199 | end; 200 | 201 | function TFilter.GetUncheckedList: TStringList; 202 | begin 203 | Result := TStringList.Create; 204 | for var I := 0 to FCheckList.Count - 1 do 205 | if FCheckList.Objects[I] = nil then 206 | Result.Add(FCheckList[I]); 207 | end; 208 | 209 | procedure TFilter.InitDefaults; 210 | begin 211 | AddFilter('apphelp.dll', FilterAll, [htImport, htDelayedImport], fsIgnore); 212 | AddFilter('kernelbase.dll', FilterAll, [htDelayedImport], fsIgnore); 213 | end; 214 | 215 | end. 216 | -------------------------------------------------------------------------------- /RawScanner/RawScanner.Logger.pas: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // **************************************************************************** 4 | // * Project : ProcessMM 5 | // * Unit Name : RawScanner.Logger.pas 6 | // * Purpose : Общий логер для всех модулей RawScanner 7 | // * Author : Александр (Rouse_) Багель 8 | // * Copyright : © Fangorn Wizards Lab 1998 - 2023. 9 | // * Version : 1.0.11 10 | // * Home Page : http://rouse.drkb.ru 11 | // * Home Blog : http://alexander-bagel.blogspot.ru 12 | // **************************************************************************** 13 | // * Stable Release : http://rouse.drkb.ru/winapi.php#pmm2 14 | // * Latest Source : https://github.com/AlexanderBagel/ProcessMemoryMap 15 | // **************************************************************************** 16 | // 17 | 18 | unit RawScanner.Logger; 19 | 20 | interface 21 | 22 | {$I rawscanner.inc} 23 | 24 | uses 25 | SysUtils; 26 | 27 | type 28 | // Типы логов 29 | TLogType = (ltNotify, ltInfo, ltWarning, ltError, ltFatal); 30 | 31 | // Уровни лога 32 | TLogLevel = ( 33 | llCore, // уведомления от базового класса 34 | llContext, // уведомления от загрузчика контекста активации 35 | llPE, // уведомления от загрузчика PE файлов 36 | llLoader, // уведомления от загрузчика таблицы лоадера 37 | llApiSet, // уведомления от парсера ApiSet таблицы 38 | llDisasm, // уведомления от модуля дизасемблирования 39 | llWow64, // уведомления от Wow64 хелпера 40 | llAnalizer // уведомления от анализатора 41 | ); 42 | 43 | TOnLogEvent = reference to procedure(ALevel: TLogLevel; AType: TLogType; 44 | const FuncName, Description: string); 45 | 46 | TRawScannerLogger = class 47 | private 48 | class var FInstance: TRawScannerLogger; 49 | class destructor ClassDestroy; 50 | private 51 | FOnLog: TOnLogEvent; 52 | procedure DoLog(ALevel: TLogLevel; AType: TLogType; 53 | const FuncName, Description: string); 54 | public 55 | procedure Notify(ALevel: TLogLevel; const Description: string); overload; 56 | procedure Notify(ALevel: TLogLevel; const FuncName, Description: string); overload; 57 | procedure Info(ALevel: TLogLevel; const Description: string); overload; 58 | procedure Info(ALevel: TLogLevel; const FuncName, Description: string); overload; 59 | procedure Warn(ALevel: TLogLevel; const Description: string); overload; 60 | procedure Warn(ALevel: TLogLevel; const FuncName, Description: string); overload; 61 | procedure Error(ALevel: TLogLevel; const Description: string); overload; 62 | procedure Error(ALevel: TLogLevel; const FuncName, Description: string); overload; 63 | procedure Fatal(ALevel: TLogLevel; const Description: string); overload; 64 | procedure Fatal(ALevel: TLogLevel; const FuncName, Description: string); overload; 65 | property OnLog: TOnLogEvent read FOnLog write FOnLog; 66 | end; 67 | 68 | function RawScannerLogger: TRawScannerLogger; 69 | 70 | implementation 71 | 72 | function RawScannerLogger: TRawScannerLogger; 73 | begin 74 | if TRawScannerLogger.FInstance = nil then 75 | TRawScannerLogger.FInstance := TRawScannerLogger.Create; 76 | Result := TRawScannerLogger.FInstance; 77 | end; 78 | 79 | { TRawScannerLogger } 80 | 81 | class destructor TRawScannerLogger.ClassDestroy; 82 | begin 83 | FreeAndNil(FInstance); 84 | end; 85 | 86 | procedure TRawScannerLogger.DoLog(ALevel: TLogLevel; AType: TLogType; 87 | const FuncName, Description: string); 88 | begin 89 | if Assigned(FOnLog) then 90 | FOnLog(ALevel, AType, FuncName, Description); 91 | end; 92 | 93 | procedure TRawScannerLogger.Error(ALevel: TLogLevel; const Description: string); 94 | begin 95 | DoLog(ALevel, ltError, EmptyStr, Description); 96 | end; 97 | 98 | procedure TRawScannerLogger.Error(ALevel: TLogLevel; const FuncName, 99 | Description: string); 100 | begin 101 | DoLog(ALevel, ltError, FuncName, Description); 102 | end; 103 | 104 | procedure TRawScannerLogger.Fatal(ALevel: TLogLevel; const Description: string); 105 | begin 106 | DoLog(ALevel, ltFatal, EmptyStr, Description); 107 | end; 108 | 109 | procedure TRawScannerLogger.Fatal(ALevel: TLogLevel; const FuncName, 110 | Description: string); 111 | begin 112 | DoLog(ALevel, ltFatal, FuncName, Description); 113 | end; 114 | 115 | procedure TRawScannerLogger.Info(ALevel: TLogLevel; const Description: string); 116 | begin 117 | DoLog(ALevel, ltInfo, EmptyStr, Description); 118 | end; 119 | 120 | procedure TRawScannerLogger.Info(ALevel: TLogLevel; const FuncName, 121 | Description: string); 122 | begin 123 | DoLog(ALevel, ltInfo, FuncName, Description); 124 | end; 125 | 126 | procedure TRawScannerLogger.Notify(ALevel: TLogLevel; const FuncName, 127 | Description: string); 128 | begin 129 | DoLog(ALevel, ltNotify, FuncName, Description); 130 | end; 131 | 132 | procedure TRawScannerLogger.Notify(ALevel: TLogLevel; 133 | const Description: string); 134 | begin 135 | DoLog(ALevel, ltNotify, EmptyStr, Description); 136 | end; 137 | 138 | procedure TRawScannerLogger.Warn(ALevel: TLogLevel; const Description: string); 139 | begin 140 | DoLog(ALevel, ltWarning, EmptyStr, Description); 141 | end; 142 | 143 | procedure TRawScannerLogger.Warn(ALevel: TLogLevel; const FuncName, 144 | Description: string); 145 | begin 146 | DoLog(ALevel, ltWarning, FuncName, Description); 147 | end; 148 | 149 | end. 150 | -------------------------------------------------------------------------------- /RawScanner/RawScanner.Types.pas: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // **************************************************************************** 4 | // * Project : ProcessMM 5 | // * Unit Name : RawScanner.Types.pas 6 | // * Purpose : Общие типы для модулей RawScanner 7 | // * Author : Александр (Rouse_) Багель 8 | // * Copyright : © Fangorn Wizards Lab 1998 - 2023. 9 | // * Version : 1.0.15 10 | // * Home Page : http://rouse.drkb.ru 11 | // * Home Blog : http://alexander-bagel.blogspot.ru 12 | // **************************************************************************** 13 | // * Stable Release : http://rouse.drkb.ru/winapi.php#pmm2 14 | // * Latest Source : https://github.com/AlexanderBagel/ProcessMemoryMap 15 | // **************************************************************************** 16 | // 17 | 18 | unit RawScanner.Types; 19 | 20 | interface 21 | 22 | {$I rawscanner.inc} 23 | 24 | uses 25 | Windows, 26 | SysUtils, 27 | Generics.Collections; 28 | 29 | const 30 | Space = ' '; 31 | Arrow = ' -> '; 32 | ReadError = 'Error reading %s at addr: 0x%.1x, code: %d, %s'; 33 | ReadErrorIndex = 'Error reading %s[I] at addr: 0x%.1x, code: %d, %s'; 34 | 35 | const 36 | IMAGE_REL_BASED_ABSOLUTE = 0; 37 | IMAGE_REL_BASED_HIGH = 1; 38 | IMAGE_REL_BASED_LOW = 2; 39 | IMAGE_REL_BASED_HIGHLOW = 3; 40 | IMAGE_REL_BASED_HIGHADJ = 4; 41 | IMAGE_REL_BASED_MIPS_JMPADDR = 5; 42 | IMAGE_REL_BASED_SECTION = 6; 43 | IMAGE_REL_BASED_REL32 = 7; 44 | IMAGE_REL_BASED_MIPS_JMPADDR16 = 8; 45 | IMAGE_REL_BASED_IA64_IMM64 = 9; 46 | IMAGE_REL_BASED_DIR64 = 10; 47 | IMAGE_REL_BASED_HIGH3ADJ = 11; 48 | 49 | type 50 | TProgressEvent = procedure(const Step: string; APecent: Integer) of object; 51 | 52 | THookType = (htImport, htDelayedImport, htExport, htCode); 53 | THookTypes = set of THookType; 54 | 55 | PULONG_PTR64 = ^ULONG_PTR64; 56 | ULONG_PTR64 = UInt64; 57 | 58 | TModuleData = record 59 | ImageBase: ULONG_PTR64; 60 | Is64Image, 61 | IsDll, 62 | IsBaseValid, 63 | IsILCoreImage, 64 | IsRedirected: Boolean; 65 | ImagePath: string; 66 | function IsEmpty: Boolean; 67 | end; 68 | TModuleList = TList; 69 | 70 | UNICODE_STRING32 = record 71 | Length, MaximumLength: USHORT; 72 | Buffer: ULONG; 73 | end; 74 | 75 | UNICODE_STRING64 = record 76 | Length, MaximumLength: USHORT; 77 | Buffer: ULONG_PTR64; 78 | end; 79 | 80 | TMemoryBasicInformation64 = record 81 | BaseAddress : ULONG_PTR64; 82 | AllocationBase : ULONG_PTR64; 83 | AllocationProtect : DWORD; 84 | RegionSize : ULONG_PTR64; 85 | State : DWORD; 86 | Protect : DWORD; 87 | Type_9 : DWORD; 88 | end; 89 | 90 | TInt64IntRec = record 91 | case Integer of 92 | 0: (Lo, Hi: Integer); 93 | 1: (Value: Int64); 94 | 2: (Rec: Int64Rec); 95 | end; 96 | 97 | implementation 98 | 99 | { TModuleData } 100 | 101 | function TModuleData.IsEmpty: Boolean; 102 | begin 103 | Result := Self.ImageBase = 0; 104 | end; 105 | 106 | end. 107 | -------------------------------------------------------------------------------- /RawScanner/RawScanner.Wow64.pas: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // **************************************************************************** 4 | // * Project : ProcessMM 5 | // * Unit Name : RawScanner.Wow64.pas 6 | // * Purpose : Модуль для поддержки WOW64 вызовов при чтении информации 7 | // * : из 32 битного процесса в 64 битном. 8 | // * Author : Александр (Rouse_) Багель 9 | // * Copyright : © Fangorn Wizards Lab 1998 - 2023. 10 | // * Version : 1.0.11 11 | // * Home Page : http://rouse.drkb.ru 12 | // * Home Blog : http://alexander-bagel.blogspot.ru 13 | // **************************************************************************** 14 | // * Stable Release : http://rouse.drkb.ru/winapi.php#pmm2 15 | // * Latest Source : https://github.com/AlexanderBagel/ProcessMemoryMap 16 | // **************************************************************************** 17 | // 18 | 19 | unit RawScanner.Wow64; 20 | 21 | interface 22 | 23 | {$I rawscanner.inc} 24 | 25 | uses 26 | Windows, 27 | SysUtils, 28 | {$IFNDEF DISABLE_LOGGER} 29 | RawScanner.Logger, 30 | {$ENDIF} 31 | RawScanner.Types; 32 | 33 | type 34 | TWow64Support = class 35 | strict private 36 | class var FInstance: TWow64Support; 37 | class destructor ClassDestroy; 38 | private 39 | FAvailable: Boolean; 40 | FDisableRedirection: function( 41 | out Wow64FsEnableRedirection: LongBool): LongBool; stdcall; 42 | FIsWow64Process: function(hProcess: THandle; 43 | var Wow64Process: LongBool): BOOL; stdcall; 44 | FRevertRedirection: function(OldValue: LongBool): LongBool; stdcall; 45 | FQueryInformationProcess64: function(ProcessHandle: THandle; 46 | ProcessInformationClass: ULONG; ProcessInformation: Pointer; 47 | ProcessInformationLength: ULONG; var ReturnLength: ULONG): DWORD; stdcall; 48 | FReadVirtualMemory64: function(ProcessHandle: THandle; 49 | BaseAddress: ULONG64; pBuffer: Pointer; Size: ULONG64; 50 | var NumberOfBytesRead: ULONG64): DWORD; stdcall; 51 | FOldRedirection: LongBool; 52 | FRedirectionCount: Integer; 53 | FUse64AddrMode: Boolean; 54 | FSystemDirectory, FSysWow64Directory: string; 55 | function Init: Boolean; 56 | public 57 | constructor Create; 58 | destructor Destroy; override; 59 | function DisableRedirection: Boolean; 60 | function EnableRedirection: Boolean; 61 | function IsWow64Process(hProcess: THandle; 62 | var Wow64Process: LongBool): BOOL; 63 | class function GetInstance: TWow64Support; 64 | function ReadVirtualMemory(hProcess: THandle; const lpBaseAddress: ULONG64; 65 | lpBuffer: Pointer; nSize: ULONG64; 66 | var lpNumberOfBytesRead: ULONG64): BOOL; 67 | function QueryInformationProcess(ProcessHandle: THandle; 68 | ProcessInformationClass: ULONG; ProcessInformation: Pointer; 69 | ProcessInformationLength: ULONG; var ReturnLength: ULONG):BOOL; 70 | property Available: Boolean read FAvailable; 71 | property Use64AddrMode: Boolean read FUse64AddrMode; 72 | property SystemDirectory: string read FSystemDirectory; 73 | property SysWow64Directory: string read FSysWow64Directory; 74 | end; 75 | 76 | function Wow64Support: TWow64Support; 77 | 78 | implementation 79 | 80 | function Wow64Support: TWow64Support; 81 | begin 82 | Result := TWow64Support.GetInstance; 83 | end; 84 | 85 | procedure Error(const Description: string); 86 | begin 87 | {$IFNDEF DISABLE_LOGGER} 88 | RawScannerLogger.Error(llWow64, Description); 89 | {$ENDIF} 90 | end; 91 | 92 | { TWow64Support } 93 | 94 | class destructor TWow64Support.ClassDestroy; 95 | begin 96 | FreeAndNil(FInstance); 97 | end; 98 | 99 | function GetSystemWow64Directory(lpBuffer: LPWSTR; uSize: UINT): UINT; stdcall; 100 | external kernel32 name 'GetSystemWow64DirectoryW'; 101 | 102 | constructor TWow64Support.Create; 103 | begin 104 | FAvailable := Init; 105 | SetLength(FSystemDirectory, MAX_PATH); 106 | SetLength(FSystemDirectory, GetSystemDirectory(@FSystemDirectory[1], MAX_PATH)); 107 | SetLength(FSysWow64Directory, MAX_PATH); 108 | SetLength(FSysWow64Directory, GetSystemWow64Directory(@FSysWow64Directory[1], MAX_PATH)); 109 | end; 110 | 111 | destructor TWow64Support.Destroy; 112 | begin 113 | if Available and (FRedirectionCount > 0) then 114 | FRevertRedirection(FOldRedirection); 115 | inherited; 116 | end; 117 | 118 | function TWow64Support.DisableRedirection: Boolean; 119 | begin 120 | Result := Available and 121 | ((FRedirectionCount > 0) or FDisableRedirection(FOldRedirection)); 122 | if Result then 123 | Inc(FRedirectionCount); 124 | end; 125 | 126 | function TWow64Support.EnableRedirection: Boolean; 127 | begin 128 | Result := Available and (FRedirectionCount > 0) and 129 | ((FRedirectionCount > 1) or FRevertRedirection(FOldRedirection)); 130 | if Result then 131 | Dec(FRedirectionCount); 132 | end; 133 | 134 | class function TWow64Support.GetInstance: TWow64Support; 135 | begin 136 | if FInstance = nil then 137 | FInstance := TWow64Support.Create; 138 | Result := FInstance; 139 | end; 140 | 141 | function TWow64Support.Init: Boolean; 142 | const 143 | StrError = 'Can not get %s module handle. Error %d %s'; 144 | var 145 | hLib: THandle; 146 | Wow64Process: LongBool; 147 | begin 148 | Result := False; 149 | hLib := GetModuleHandle('kernel32.dll'); 150 | if hLib <= HINSTANCE_ERROR then 151 | begin 152 | Error( 153 | Format(StrError, ['kernel32.dll', GetLastError, SysErrorMessage(GetLastError)])); 154 | Exit; 155 | end; 156 | FIsWow64Process := GetProcAddress(hLib, 'IsWow64Process'); 157 | FDisableRedirection := GetProcAddress(hLib, 'Wow64DisableWow64FsRedirection'); 158 | FRevertRedirection := GetProcAddress(hLib, 'Wow64RevertWow64FsRedirection'); 159 | hLib := GetModuleHandle('ntdll.dll'); 160 | if hLib <= HINSTANCE_ERROR then 161 | begin 162 | Error( 163 | Format(StrError, ['ntdll.dll', GetLastError, SysErrorMessage(GetLastError)])); 164 | Exit; 165 | end; 166 | FQueryInformationProcess64 := GetProcAddress(hLib, 'NtWow64QueryInformationProcess64'); 167 | FReadVirtualMemory64 := GetProcAddress(hLib, 'NtWow64ReadVirtualMemory64'); 168 | Result := 169 | Assigned(FDisableRedirection) and 170 | Assigned(FIsWow64Process) and 171 | Assigned(FRevertRedirection) and 172 | Assigned(FQueryInformationProcess64) and 173 | Assigned(FReadVirtualMemory64) and 174 | FIsWow64Process(GetCurrentProcess, Wow64Process) and 175 | Wow64Process; 176 | if Result then 177 | FUse64AddrMode := Wow64Process; 178 | end; 179 | 180 | function TWow64Support.IsWow64Process(hProcess: THandle; 181 | var Wow64Process: LongBool): BOOL; 182 | begin 183 | Result := Assigned(FIsWow64Process) and 184 | FIsWow64Process(hProcess, Wow64Process); 185 | end; 186 | 187 | function TWow64Support.QueryInformationProcess(ProcessHandle: THandle; 188 | ProcessInformationClass: ULONG; ProcessInformation: Pointer; 189 | ProcessInformationLength: ULONG; var ReturnLength: ULONG): BOOL; 190 | begin 191 | Result := Available and (FQueryInformationProcess64(ProcessHandle, 192 | ProcessInformationClass, ProcessInformation, ProcessInformationLength, 193 | ReturnLength) = 0); 194 | end; 195 | 196 | function TWow64Support.ReadVirtualMemory(hProcess: THandle; const lpBaseAddress: ULONG64; 197 | lpBuffer: Pointer; nSize: ULONG64; var lpNumberOfBytesRead: ULONG64): BOOL; 198 | begin 199 | Result := Available and (FReadVirtualMemory64(hProcess, lpBaseAddress, 200 | lpBuffer, nSize, lpNumberOfBytesRead) = 0); 201 | end; 202 | 203 | end. 204 | -------------------------------------------------------------------------------- /RawScanner/RawScanner.X64Gates.pas: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // **************************************************************************** 4 | // * Project : ProcessMM 5 | // * Unit Name : RawScanner.X64Gates.pas 6 | // * Purpose : Генератор шлюзов вызова 64 битных stdcall API 7 | // * Author : Александр (Rouse_) Багель 8 | // * Copyright : © Fangorn Wizards Lab 1998 - 2023. 9 | // * Version : 1.0.11 10 | // * Home Page : http://rouse.drkb.ru 11 | // * Home Blog : http://alexander-bagel.blogspot.ru 12 | // **************************************************************************** 13 | // * Stable Release : http://rouse.drkb.ru/winapi.php#pmm2 14 | // * Latest Source : https://github.com/AlexanderBagel/ProcessMemoryMap 15 | // **************************************************************************** 16 | // 17 | 18 | unit RawScanner.X64Gates; 19 | 20 | interface 21 | 22 | {$I rawscanner.inc} 23 | 24 | uses 25 | Windows, 26 | SysUtils, 27 | Math, 28 | RawScanner.Types; 29 | 30 | type 31 | TParamSize = (ps4Byte = 2, ps8Byte = 3{, psXMM - XMM пока не поддерживается}); 32 | 33 | /// 34 | /// MakeX64Gate - генерирует шлюз вызова 64 битной API функции. 35 | /// FuncAddr - адрес 64 битной stdcall функции в текущем процессе 36 | /// Params - массив размеров параметров на 32 битном стеке 37 | /// 38 | function MakeX64Gate(FuncAddr: ULONG_PTR64; Params: array of TParamSize): Pointer; 39 | procedure ReleaseX64Gate(Value: Pointer); 40 | 41 | implementation 42 | 43 | function MakeX64Gate(FuncAddr: ULONG_PTR64; Params: array of TParamSize): Pointer; 44 | {$IFDEF WIN64} 45 | begin 46 | Result := Pointer(FuncAddr); 47 | {$ELSE} 48 | 49 | var 50 | InsPoint: PByte; 51 | 52 | procedure Push(Instructions: array of Byte); 53 | begin 54 | Move(Instructions[0], InsPoint^, Length(Instructions)); 55 | Inc(InsPoint, Length(Instructions)); 56 | end; 57 | 58 | procedure PushDWord(Value: DWORD); 59 | begin 60 | Move(Value, InsPoint^, 4); 61 | Inc(InsPoint, 4); 62 | end; 63 | 64 | procedure PushDWord64(Value: DWORD64); 65 | begin 66 | Move(Value, InsPoint^, 8); 67 | Inc(InsPoint, 8); 68 | end; 69 | 70 | var 71 | I, ParamsCount, ShadowSpace, ParamSize, ParamsLeft: Integer; 72 | x32StackPtr, x64StackPtr: Byte; 73 | begin 74 | Result := VirtualAlloc(nil, 4096, MEM_COMMIT, PAGE_EXECUTE_READWRITE); 75 | InsPoint := Result; 76 | 77 | if Result = nil then 78 | RaiseLastOSError; 79 | 80 | // рассчет количества и общего размера переданых параметров 81 | ParamsCount := Length(Params); 82 | 83 | // в автогенерации используются короткие инструкции работающие с байтом 84 | // поэтому нужен контроль чтобы ParamsCount * 8 не вылез за его пределы 85 | if ParamsCount > 31 then 86 | raise Exception.Create('Too many params'); 87 | 88 | ParamSize := 0; 89 | for I := 0 to ParamsCount - 1 do 90 | Inc(ParamSize, 1 shl Byte(Params[I])); 91 | // Теневое пространство требует минимум 32 байта под 4 дефолтных регистра 92 | ShadowSpace := Max(32, ParamsCount * 8); 93 | 94 | // пролог 95 | Push([$55]); // push ebp 96 | Push([$8B, $EC]); // mov ebp, esp 97 | 98 | // выравнивание стека 99 | Push([$89, $E0]); // mov eax, esp 100 | Push([$83, $E0, $07]); // and eax, $07 101 | Push([$83, $F8, $00]); // cmp eax, $00 102 | Push([$74, $02]); // jz +2 103 | Push([$29, $C4]); // sub esp, eax 104 | 105 | // переключение в 64 битный режим 106 | Push([$EA]); // jmp far 0x33:+SizeOf(jmp) 107 | PushDWord(DWORD(InsPoint) + 6); 108 | Push([$33, 0]); 109 | 110 | // формирование 64 битного фрейма 111 | Push([$55]); // push rbp 112 | Push([$48, $83, $EC, ShadowSpace]); // sub rsp, 64 ShadowSpace 113 | Push([$48, $89, $E5]); // mov rbp, rsp 114 | 115 | // перенос параметров для 64 битного вызова 116 | 117 | if ParamsCount > 0 then 118 | begin 119 | // выставление указателя на последний параметр с 32 битного стека 120 | Push([$48, $8D, $84, $04]); // lea rax, [rsp + rax + ...] 121 | PushDWord( 122 | ShadowSpace + // размер 64 битного теневого пространства 123 | 8 + // 64 битный push rbp 124 | ParamSize + // размер 32 битных параметров 125 | 4 + // 32 битный push ebp 126 | 4 // 32 битный адрес возврата 127 | ); 128 | ParamsLeft := ParamsCount - 1; 129 | x32StackPtr := 0; 130 | x64StackPtr := ShadowSpace; 131 | while ParamsLeft >= 0 do 132 | begin 133 | // сдвигаем указатель на начало следующего параметра на 32 битном стеке 134 | Inc(x32StackPtr, 1 shl Byte(Params[ParamsLeft])); 135 | case ParamsLeft of 136 | 0: // mov rcx(ecx), [rax - x32StackPtr]] 137 | begin 138 | if Params[ParamsLeft] = ps8Byte then 139 | Push([$48]); // REX Pfx здесь и далее. Используется для модификации ecx->rcx 140 | Push([$8B, $48, Byte(-x32StackPtr)]); 141 | end; 142 | 1: // mov rdx(edx), [rax - x32StackPtr] 143 | begin 144 | if Params[ParamsLeft] = ps8Byte then 145 | Push([$48]); 146 | Push([$8B, $50, Byte(-x32StackPtr)]); 147 | end; 148 | 2: // mov r8(r8d), [rax - x32StackPtr] 149 | begin 150 | if Params[ParamsLeft] = ps8Byte then 151 | Push([$4C, $8B, $40, Byte(-x32StackPtr)]) 152 | else 153 | Push([$44, $8B, $40, Byte(-x32StackPtr)]); 154 | end; 155 | 3: // mov r9(r9d), [rax - x32StackPtr] 156 | begin 157 | if Params[ParamsLeft] = ps8Byte then 158 | Push([$4C, $8B, $48, Byte(-x32StackPtr)]) 159 | else 160 | Push([$44, $8B, $48, Byte(-x32StackPtr)]); 161 | end; 162 | else 163 | // mov rcx(ecx), [rax - x32StackPtr] 164 | if Params[ParamsLeft] = ps8Byte then 165 | Push([$48]); 166 | Push([$8B, $48, Byte(-x32StackPtr)]); 167 | Dec(x64StackPtr, 8); 168 | // mov [rsp + "оффсет на 64 битный параметр на сетке"], rcx 169 | Push([$48, $89, $4C, $24, x64StackPtr]); 170 | end; 171 | Dec(ParamsLeft); 172 | end; 173 | end; 174 | 175 | // вызов фунции 176 | Push([$48, $B8]); // mov rax, FuncAddr 177 | PushDWord64(FuncAddr); 178 | Push([$FF, $D0]); // call rax 179 | 180 | // перемещение результата из RAX в пару EAX + EDX 181 | Push([$48, $89, $C2]); // mov rdx, rax 182 | Push([$48, $C1, $EA, $20]); // shr rdx, $20 183 | 184 | // закрытие 64 битного фрейма 185 | Push([$48, $83, $C4, ShadowSpace]); // add rsp, 64 ShadowSpace 186 | Push([$5D]); // pop rbp 187 | 188 | // переключение в 32 битный режим 189 | Push([$FF, $2D, 0, 0, 0, 0]); // jmp far word ptr ds:[0] 190 | PushDWord(DWORD(InsPoint) + 6); // jmp addr 191 | Push([$23, 0]); // CS param 192 | 193 | // восстановление 32 битного стека 194 | Push([$89, $EC]); // mov esp, ebp 195 | 196 | // эпилог 197 | Push([$5D]); // pop ebp 198 | Push([$C2, ParamSize, 0]); // ret + 32 params size 199 | {$ENDIF} 200 | end; 201 | 202 | procedure ReleaseX64Gate(Value: Pointer); 203 | begin 204 | {$IFDEF WIN32} 205 | if Value <> nil then 206 | VirtualFree(Value, 0, MEM_RELEASE); 207 | {$ENDIF} 208 | end; 209 | 210 | end. 211 | -------------------------------------------------------------------------------- /RawScanner/demo/raw_image.dpr: -------------------------------------------------------------------------------- 1 | program raw_image; 2 | 3 | {$APPTYPE CONSOLE} 4 | 5 | {$R *.res} 6 | 7 | uses 8 | Windows, 9 | System.SysUtils, 10 | Classes, 11 | MMSystem, 12 | Math, 13 | System.TypInfo, 14 | Generics.Collections, 15 | RawScanner.Analyzer in '..\RawScanner.Analyzer.pas', 16 | RawScanner.Wow64 in '..\RawScanner.Wow64.pas', 17 | RawScanner.LoaderData in '..\RawScanner.LoaderData.pas', 18 | RawScanner.Types in '..\RawScanner.Types.pas', 19 | RawScanner.Utils in '..\RawScanner.Utils.pas', 20 | distorm in '..\..\distorm\distorm.pas', 21 | mnemonics in '..\..\distorm\mnemonics.pas', 22 | RawScanner.Disassembler in '..\RawScanner.Disassembler.pas', 23 | RawScanner.ApiSet in '..\RawScanner.ApiSet.pas', 24 | RawScanner.Logger in '..\RawScanner.Logger.pas', 25 | RawScanner.Filter in '..\RawScanner.Filter.pas', 26 | display_utils in 'display_utils.pas', 27 | RawScanner.ActivationContext in '..\RawScanner.ActivationContext.pas', 28 | RawScanner.Core in '..\RawScanner.Core.pas', 29 | RawScanner.SymbolStorage in '..\RawScanner.SymbolStorage.pas', 30 | RawScanner.X64Gates in '..\RawScanner.X64Gates.pas', 31 | RawScanner.CoffDwarf in '..\RawScanner.CoffDwarf.pas', 32 | RawScanner.AbstractImage in '..\RawScanner.AbstractImage.pas', 33 | RawScanner.Image.Pe in '..\RawScanner.Image.Pe.pas'; 34 | 35 | var 36 | AProcessID: DWORD; 37 | I: Integer; 38 | begin 39 | Writeln(Win32MajorVersion, '.', Win32MinorVersion, '.', Win32BuildNumber, '.', 40 | Win32Platform, ' ', Win32CSDVersion); 41 | 42 | // заменить PID на любой другой сторонний процесс!!! 43 | AProcessID := GetCurrentProcessId; 44 | 45 | RawScannerLogger.OnLog := OnLog; 46 | 47 | RawScannerCore.InitFromProcess(AProcessID); 48 | 49 | Writeln('Loader32: ', RawScannerCore.InitializationResult.Loader32); 50 | Writeln('Loader64: ', RawScannerCore.InitializationResult.Loader64); 51 | Writeln('Use64AddrMode: ', Wow64Support.Use64AddrMode); 52 | 53 | 54 | for I := 0 to RawScannerCore.Modules.Items.Count - 1 do 55 | ShowModuleInfo(I, RawScannerCore.Modules.Items[I]); 56 | 57 | Filter := TFilter.Create; 58 | try 59 | 60 | try 61 | RawScannerCore.Analizer.Analyze( 62 | // обработка вывода перехваченых таблиц импорта/экспорта 63 | ProcessTableHook, 64 | // обработка вывода перехватчиков установленых непосредственно в коде функций 65 | ProcessCodeHook 66 | ); 67 | 68 | except 69 | on E: Exception do 70 | Writeln(E.ClassName, ': ', E.Message); 71 | end; 72 | 73 | Writeln; 74 | 75 | // вывод результатов работы фильтра 76 | var UncheckedCount := Filter.GetUncheckedCount; 77 | Writeln('Total filtered: ', GlobalFiltered); 78 | Writeln('Total filter unchecked: ', UncheckedCount); 79 | Writeln('Total filter checked: ', GlobalChecked); 80 | 81 | finally 82 | Filter.Free; 83 | end; 84 | 85 | Writeln; 86 | Writeln('DONE!'); 87 | readln; 88 | end. 89 | 90 | 91 | -------------------------------------------------------------------------------- /RawScanner/rawscanner.inc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexanderBagel/ProcessMemoryMap/c5dc46ff63fb0fa20f6728abed0214786f91e4a2/RawScanner/rawscanner.inc -------------------------------------------------------------------------------- /cpu_view.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexanderBagel/ProcessMemoryMap/c5dc46ff63fb0fa20f6728abed0214786f91e4a2/cpu_view.ico -------------------------------------------------------------------------------- /distorm/32/decoder.obj: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexanderBagel/ProcessMemoryMap/c5dc46ff63fb0fa20f6728abed0214786f91e4a2/distorm/32/decoder.obj -------------------------------------------------------------------------------- /distorm/32/distorm.obj: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexanderBagel/ProcessMemoryMap/c5dc46ff63fb0fa20f6728abed0214786f91e4a2/distorm/32/distorm.obj -------------------------------------------------------------------------------- /distorm/32/instructions.obj: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexanderBagel/ProcessMemoryMap/c5dc46ff63fb0fa20f6728abed0214786f91e4a2/distorm/32/instructions.obj -------------------------------------------------------------------------------- /distorm/32/insts.obj: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexanderBagel/ProcessMemoryMap/c5dc46ff63fb0fa20f6728abed0214786f91e4a2/distorm/32/insts.obj -------------------------------------------------------------------------------- /distorm/32/mnemonics.obj: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexanderBagel/ProcessMemoryMap/c5dc46ff63fb0fa20f6728abed0214786f91e4a2/distorm/32/mnemonics.obj -------------------------------------------------------------------------------- /distorm/32/operands.obj: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexanderBagel/ProcessMemoryMap/c5dc46ff63fb0fa20f6728abed0214786f91e4a2/distorm/32/operands.obj -------------------------------------------------------------------------------- /distorm/32/prefix.obj: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexanderBagel/ProcessMemoryMap/c5dc46ff63fb0fa20f6728abed0214786f91e4a2/distorm/32/prefix.obj -------------------------------------------------------------------------------- /distorm/32/textdefs.obj: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexanderBagel/ProcessMemoryMap/c5dc46ff63fb0fa20f6728abed0214786f91e4a2/distorm/32/textdefs.obj -------------------------------------------------------------------------------- /distorm/64/decoder.obj: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexanderBagel/ProcessMemoryMap/c5dc46ff63fb0fa20f6728abed0214786f91e4a2/distorm/64/decoder.obj -------------------------------------------------------------------------------- /distorm/64/distorm.obj: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexanderBagel/ProcessMemoryMap/c5dc46ff63fb0fa20f6728abed0214786f91e4a2/distorm/64/distorm.obj -------------------------------------------------------------------------------- /distorm/64/instructions.obj: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexanderBagel/ProcessMemoryMap/c5dc46ff63fb0fa20f6728abed0214786f91e4a2/distorm/64/instructions.obj -------------------------------------------------------------------------------- /distorm/64/insts.obj: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexanderBagel/ProcessMemoryMap/c5dc46ff63fb0fa20f6728abed0214786f91e4a2/distorm/64/insts.obj -------------------------------------------------------------------------------- /distorm/64/mnemonics.obj: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexanderBagel/ProcessMemoryMap/c5dc46ff63fb0fa20f6728abed0214786f91e4a2/distorm/64/mnemonics.obj -------------------------------------------------------------------------------- /distorm/64/operands.obj: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexanderBagel/ProcessMemoryMap/c5dc46ff63fb0fa20f6728abed0214786f91e4a2/distorm/64/operands.obj -------------------------------------------------------------------------------- /distorm/64/prefix.obj: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexanderBagel/ProcessMemoryMap/c5dc46ff63fb0fa20f6728abed0214786f91e4a2/distorm/64/prefix.obj -------------------------------------------------------------------------------- /distorm/64/textdefs.obj: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexanderBagel/ProcessMemoryMap/c5dc46ff63fb0fa20f6728abed0214786f91e4a2/distorm/64/textdefs.obj -------------------------------------------------------------------------------- /doc/DWARF4.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexanderBagel/ProcessMemoryMap/c5dc46ff63fb0fa20f6728abed0214786f91e4a2/doc/DWARF4.pdf -------------------------------------------------------------------------------- /doc/DWARF5.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexanderBagel/ProcessMemoryMap/c5dc46ff63fb0fa20f6728abed0214786f91e4a2/doc/DWARF5.pdf -------------------------------------------------------------------------------- /doc/Dwarf3.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexanderBagel/ProcessMemoryMap/c5dc46ff63fb0fa20f6728abed0214786f91e4a2/doc/Dwarf3.pdf -------------------------------------------------------------------------------- /doc/dwarf-2.0.0.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexanderBagel/ProcessMemoryMap/c5dc46ff63fb0fa20f6728abed0214786f91e4a2/doc/dwarf-2.0.0.pdf -------------------------------------------------------------------------------- /doc/improving-x64-bin-analysis.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexanderBagel/ProcessMemoryMap/c5dc46ff63fb0fa20f6728abed0214786f91e4a2/doc/improving-x64-bin-analysis.pdf -------------------------------------------------------------------------------- /doc/os-debugging-pdf.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexanderBagel/ProcessMemoryMap/c5dc46ff63fb0fa20f6728abed0214786f91e4a2/doc/os-debugging-pdf.pdf -------------------------------------------------------------------------------- /img/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexanderBagel/ProcessMemoryMap/c5dc46ff63fb0fa20f6728abed0214786f91e4a2/img/1.png -------------------------------------------------------------------------------- /img/10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexanderBagel/ProcessMemoryMap/c5dc46ff63fb0fa20f6728abed0214786f91e4a2/img/10.png -------------------------------------------------------------------------------- /img/11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexanderBagel/ProcessMemoryMap/c5dc46ff63fb0fa20f6728abed0214786f91e4a2/img/11.png -------------------------------------------------------------------------------- /img/12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexanderBagel/ProcessMemoryMap/c5dc46ff63fb0fa20f6728abed0214786f91e4a2/img/12.png -------------------------------------------------------------------------------- /img/14.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexanderBagel/ProcessMemoryMap/c5dc46ff63fb0fa20f6728abed0214786f91e4a2/img/14.png -------------------------------------------------------------------------------- /img/15.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexanderBagel/ProcessMemoryMap/c5dc46ff63fb0fa20f6728abed0214786f91e4a2/img/15.png -------------------------------------------------------------------------------- /img/16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexanderBagel/ProcessMemoryMap/c5dc46ff63fb0fa20f6728abed0214786f91e4a2/img/16.png -------------------------------------------------------------------------------- /img/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexanderBagel/ProcessMemoryMap/c5dc46ff63fb0fa20f6728abed0214786f91e4a2/img/2.png -------------------------------------------------------------------------------- /img/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexanderBagel/ProcessMemoryMap/c5dc46ff63fb0fa20f6728abed0214786f91e4a2/img/3.png -------------------------------------------------------------------------------- /img/4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexanderBagel/ProcessMemoryMap/c5dc46ff63fb0fa20f6728abed0214786f91e4a2/img/4.png -------------------------------------------------------------------------------- /img/5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexanderBagel/ProcessMemoryMap/c5dc46ff63fb0fa20f6728abed0214786f91e4a2/img/5.png -------------------------------------------------------------------------------- /img/6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexanderBagel/ProcessMemoryMap/c5dc46ff63fb0fa20f6728abed0214786f91e4a2/img/6.png -------------------------------------------------------------------------------- /img/7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexanderBagel/ProcessMemoryMap/c5dc46ff63fb0fa20f6728abed0214786f91e4a2/img/7.png -------------------------------------------------------------------------------- /img/8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexanderBagel/ProcessMemoryMap/c5dc46ff63fb0fa20f6728abed0214786f91e4a2/img/8.png -------------------------------------------------------------------------------- /img/9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexanderBagel/ProcessMemoryMap/c5dc46ff63fb0fa20f6728abed0214786f91e4a2/img/9.png -------------------------------------------------------------------------------- /plugins/include/pmm_plugin.h: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // **************************************************************************** 4 | // * Project : ProcessMM 5 | // * Unit Name : pmm_plugin.h 6 | // * Purpose : Модуль с декларацией структур для плагинов PMM 7 | // * Author : Александр (Rouse_) Багель 8 | // * Copyright : © Fangorn Wizards Lab 1998 - 2023. 9 | // * Version : 1.0.1 10 | // * Home Page : http://rouse.drkb.ru 11 | // * Home Blog : http://alexander-bagel.blogspot.ru 12 | // **************************************************************************** 13 | // * Stable Release : http://rouse.drkb.ru/winapi.php#pmm2 14 | // * Latest Source : https://github.com/AlexanderBagel/ProcessMemoryMap 15 | // **************************************************************************** 16 | // 17 | 18 | #ifndef pmm_pluginH 19 | #define pmm_pluginH 20 | 21 | #include 22 | 23 | /* 24 | Для облегчения отладки плагина можно использовать командную строку. 25 | 1. В параметрах запуска указать путь к утилите (Host application). 26 | Например: ..\..\..\..\Win64\SingleInstance\ProcessMM.exe 27 | 2. В командной строке прописать параметры запуска утилиты в формате 28 | "Идентификатор процесса" (int), "Адрес страницы" ($HEX), "режим дизассеблирования" (-d) 29 | Например: 27992 $00540000 -d 30 | 3. Для отладки 32 битной библиотеки необходимо переключить РММ в 32 битный режим 31 | принудительно выставлением флага x32 (только для 64 битных ОС) 32 | Например: x32 27992 $00540000 -d 33 | */ 34 | 35 | 36 | /// 37 | /// версия API на которой был собран плагин, должна возвращаться в Plugin.VersionApi 38 | /// 39 | 40 | const int PMM_API_VER = 1; 41 | 42 | /// 43 | /// плагин должен экспортировать эту функцию, возвращающую структуру Plugin 44 | /// 45 | 46 | const char PMM_PLUGIN_ENTRYPOINT_NAME[] = "pmm_get_plugin_info"; 47 | 48 | /// 49 | /// двусвязный список передаваемый на вход PluginOpenProcess 50 | /// 51 | 52 | struct ProcessModule 53 | { 54 | struct ProcessModule *BLink; // ссылка на предыдущую структуру (или nil) 55 | struct ProcessModule *FLink; // ссылка на следующую структуру (nil - конец списка) 56 | ULONG64 Instance; // база загрузки модуля в открытом хостом процессе 57 | wchar_t *ImagePath; // полный путь к модулю 58 | BOOL LoadAsDataFile; // флаг присутствия модуля в списках лоадера (исполняемый или отмапленый) 59 | }; 60 | 61 | /// 62 | /// Тип дескриптора 63 | /// 64 | /// 65 | enum DescriptorType { 66 | 67 | /// 68 | /// Флаг типа дескриптора, означающий произвольные данные, описываемые им, например коментарий 69 | /// 70 | PMM_DESCR_TYPE_UNKNOWN = 0, 71 | 72 | /// 73 | /// Флаг типа дескриптора, означающий что дескриптор описывает поле структуры 74 | /// При это в TDescriptorData желательно заполнение наименования структуры в поле NameSpace 75 | /// 76 | PMM_DESCR_TYPE_STRUCT = 1, 77 | 78 | /// 79 | /// Флаг типа дескриптора, означающий что дескриптор описывает функцию 80 | /// 81 | PMM_DESCR_TYPE_FUNCTION = 2 82 | 83 | }; 84 | 85 | struct Descriptor 86 | { 87 | ULONG64 AddrVA; // описываемый адрес 88 | HANDLE Handle; // уникальный маркер задаваемый плагином 89 | DescriptorType DescrType; // тип дескриптора 90 | }; 91 | 92 | /// 93 | /// данные описываемые дескриптором 94 | /// 95 | 96 | struct DescriptorData 97 | { 98 | wchar_t *Caption; // описание адреса, например имя функции или имя поля структуры 99 | // необязательные поля (не используются в режиме дизассемблера) 100 | wchar_t *NameSpace; // принадлежность адреса к более обьемному блоку (например структуре или таблице) 101 | wchar_t *Description; // коментарий у адресу 102 | DWORD Size; // размер описываемого блока 103 | }; 104 | 105 | /// 106 | /// адреса функций посредством которых идет работа с плагином 107 | /// Close является не обязательны и может быть не назначен. 108 | /// 109 | 110 | struct PluginCallGate 111 | { 112 | /// 113 | /// команда плагину об открытии нового процесса (нужно инициализароваться) 114 | /// в случае успеха фунция должна вернуть NO_ERROR 115 | /// 116 | DWORD (WINAPI *PluginOpenProcess)(DWORD, struct ProcessModule *); 117 | /// 118 | /// команда плагину о закрытии процесса (нужно освободить ресурсы) 119 | /// 120 | void (WINAPI *PluginCloseProcess)(); 121 | /// 122 | /// запрос о количестве известных плагину дескрипторов 123 | /// в случае неуспеха функция должна вернуть ноль! 124 | /// 125 | int (WINAPI *PluginDescriptorCount)(); 126 | /// 127 | /// запрос дескриптора по индексу 128 | /// 129 | DWORD (WINAPI *PluginGetDescriptor)(int, struct Descriptor *); 130 | /// 131 | /// запрос данных дескриптора. Память должна быть выделена вызывающей стороной. 132 | /// необходимый размер данных возвращается в параметре pSize 133 | /// AHandle - параметр полученый ранее из структуры TDescriptor 134 | /// Если pDescData равна NIL или pSize содержит недостаточный размер 135 | /// функция обязана вернуть ERROR_INSUFFICIENT_BUFFER 136 | /// В случае успеха функция должна вернуть NO_ERROR 137 | /// 138 | DWORD (WINAPI *PluginGetDescriptorData)(HANDLE, struct DescriptorData *, UINT32 *); 139 | }; 140 | 141 | /// 142 | /// структура возвращаемая pmm_get_plugin_info() 143 | /// 144 | 145 | struct Plugin 146 | { 147 | DWORD VersionApi; // поле должно быть заполнено значением PMM_API_VER 148 | DWORD PluginUID; // уникальный идентификатор плагина. 149 | // не должен быть равен нулю и 150 | // не должен меняться при выпуске новой версии плагина!!! 151 | struct PluginCallGate Gate; // шлюз вызовов плагина 152 | 153 | // следующие поля не обязательны и могут быть равны nil 154 | const wchar_t *PluginName; // имя плагина (используется в диалоге прогресса) 155 | const wchar_t *PluginAuthor; // автор плагина 156 | const wchar_t *PluginHomePage; // домашняя страницы плагина 157 | const wchar_t *PluginDescription; // краткое описание плагина 158 | }; 159 | 160 | /// 161 | /// точка входа в плагин. именно с неё начинается работа 162 | /// 163 | 164 | __declspec(dllexport) struct Plugin WINAPI pmm_get_plugin_info(); 165 | 166 | #endif // pmm_pluginH -------------------------------------------------------------------------------- /plugins/include/pmm_plugin.pas: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // **************************************************************************** 4 | // * Project : ProcessMM 5 | // * Unit Name : pmm_plugin.pas 6 | // * Purpose : Модуль с декларацией структур для плагинов PMM 7 | // * Author : Александр (Rouse_) Багель 8 | // * Copyright : © Fangorn Wizards Lab 1998 - 2023. 9 | // * Version : 1.3.23 10 | // * Home Page : http://rouse.drkb.ru 11 | // * Home Blog : http://alexander-bagel.blogspot.ru 12 | // **************************************************************************** 13 | // * Stable Release : http://rouse.drkb.ru/winapi.php#pmm2 14 | // * Latest Source : https://github.com/AlexanderBagel/ProcessMemoryMap 15 | // **************************************************************************** 16 | // 17 | 18 | unit pmm_plugin; 19 | 20 | interface 21 | 22 | uses 23 | Windows; 24 | 25 | { 26 | Для облегчения отладки плагина можно использовать командную строку. 27 | 1. В параметрах запуска указать путь к утилите (Host application). 28 | Например: ..\..\..\..\Win64\SingleInstance\ProcessMM.exe 29 | 2. В командной строке прописать параметры запуска утилиты в формате 30 | "Идентификатор процесса" (int), "Адрес страницы" ($HEX), "режим дизассеблирования" (-d) 31 | Например: 27992 $00540000 -d 32 | 3. Для отладки 32 битной библиотеки необходимо переключить РММ в 32 битный режим 33 | принудительно выставлением флага x32 (только для 64 битных ОС) 34 | Например: x32 27992 $00540000 -d 35 | } 36 | 37 | const 38 | /// 39 | /// версия API на которой был собран плагин, должна возвращаться в TPlugin.VersionApi 40 | /// 41 | PMM_API_VER = 1; 42 | 43 | /// 44 | /// плагин должен экспортировать эту функцию, возвращающую структуру TPlugin 45 | /// 46 | PMM_PLUGIN_ENTRYPOINT_NAME = 'pmm_get_plugin_info'; 47 | 48 | type 49 | /// 50 | /// двусвязный список передаваемый на вход TPluginOpenProcess 51 | /// 52 | PProcessModule = ^TProcessModule; 53 | TProcessModule = record 54 | BLink: PProcessModule; // ссылка на предыдущую структуру (или nil) 55 | FLink: PProcessModule; // ссылка на следующую структуру (nil - конец списка) 56 | Instance: ULONG64; // база загрузки модуля в открытом хостом процессе 57 | ImagePath: PWideChar; // полный путь к модулю 58 | LoadAsDataFile: BOOL; // флаг присутствия модуля в списках лоадера (исполняемый или отмапленый) 59 | end; 60 | 61 | /// 62 | /// команда плагину об открытии нового процесса (нужно инициализароваться) 63 | /// в случае успеха фунция должна вернуть NO_ERROR 64 | /// 65 | TPluginOpenProcess = 66 | function(AProcessID: DWORD; AModuleList: PProcessModule): DWORD; stdcall; 67 | 68 | /// 69 | /// команда плагину о закрытии процесса (нужно освободить ресурсы) 70 | /// 71 | TPluginCloseProcess = procedure(); stdcall; 72 | 73 | /// 74 | /// запрос о количестве известных плагину дескрипторов 75 | /// в случае неуспеха функция должна вернуть ноль! 76 | /// 77 | TPluginDescriptorCount = function(): Integer; stdcall; 78 | 79 | /// 80 | /// Тип дескриптора 81 | /// 82 | TDescriptorType = ( 83 | 84 | /// 85 | /// Флаг типа дескриптора, означающий произвольные данные, описываемые им, например коментарий 86 | /// 87 | PMM_DESCR_TYPE_UNKNOWN = 0, 88 | 89 | /// 90 | /// Флаг типа дескриптора, означающий что дескриптор описывает поле структуры 91 | /// При это в TDescriptorData желательно заполнение наименования структуры в поле NameSpace 92 | /// 93 | PMM_DESCR_TYPE_STRUCT = 1, 94 | 95 | /// 96 | /// Флаг типа дескриптора, означающий что дескриптор описывает функцию 97 | /// 98 | PMM_DESCR_TYPE_FUNCTION = 2 99 | ); 100 | 101 | /// 102 | /// уникальный описатель известной плагину информации по адресу 103 | /// 104 | PDescriptor = ^TDescriptor; 105 | TDescriptor = record 106 | AddrVA: ULONG64; // описываемый адрес 107 | Handle: THandle; // уникальный маркер задаваемый плагином 108 | DescrType: TDescriptorType; // тип дескриптора 109 | end; 110 | 111 | /// 112 | /// запрос дескриптора по индексу 113 | /// 114 | TPluginGetDescriptor = function(Index: Integer; pDesc: PDescriptor): DWORD; stdcall; 115 | 116 | /// 117 | /// данные описываемые дескриптором 118 | /// 119 | PDescriptorData = ^TDescriptorData; 120 | TDescriptorData = record 121 | Caption: PWideChar; // описание адреса, например имя функции или имя поля структуры 122 | // необязательные поля (не используются в режиме дизассемблера) 123 | NameSpace: PWideChar; // принадлежность адреса к более обьемному блоку (например структуре или таблице) 124 | Description: PWideChar; // коментарий к адресу 125 | Size: DWORD; // размер описываемого блока 126 | end; 127 | 128 | /// 129 | /// запрос данных дескриптора. Память должна быть выделена вызывающей стороной. 130 | /// необходимый размер данных возвращается в параметре pSize 131 | /// AHandle - параметр полученый ранее из структуры TDescriptor 132 | /// Если pDescData равна NIL или pSize содержит недостаточный размер 133 | /// функция обязана вернуть ERROR_INSUFFICIENT_BUFFER 134 | /// В случае успеха функция должна вернуть NO_ERROR 135 | /// 136 | TPluginGetDescriptorData = function(AHandle: THandle; 137 | pDescData: PDescriptorData; pSize: PInteger): DWORD; stdcall; 138 | 139 | /// 140 | /// адреса функций посредством которых идет работа с плагином 141 | /// Close является не обязательны и может быть не назначен. 142 | /// 143 | TPluginCallGate = record 144 | Open: TPluginOpenProcess; 145 | Close: TPluginCloseProcess; 146 | DescriptorCount: TPluginDescriptorCount; 147 | GetDescriptor: TPluginGetDescriptor; 148 | GetDescriptorData: TPluginGetDescriptorData; 149 | end; 150 | 151 | /// 152 | /// структура возвращаемая pmm_get_plugin_info() 153 | /// 154 | TPlugin = record 155 | VersionApi: DWORD; // поле должно быть заполнено значением PMM_API_VER 156 | PluginUID: DWORD; // уникальный идентификатор плагина. 157 | // не должен быть равен нулю и 158 | // не должен меняться при выпуске новой версии плагина!!! 159 | 160 | Gate: TPluginCallGate; // шлюз вызовов плагина 161 | 162 | // следующие поля не обязательны и могут быть равны nil 163 | PluginName: PWideChar; // имя плагина (используется в диалоге прогресса) 164 | PluginAuthor: PWideChar; // автор плагина 165 | PluginHomePage: PWideChar; // домашняя страницы плагина 166 | PluginDesсription: PWideChar; // краткое описание плагина 167 | end; 168 | 169 | /// 170 | /// точка входа в плагин. именно с неё начинается работа 171 | /// 172 | Tpmm_get_plugin_info = function(): TPlugin; stdcall; 173 | 174 | implementation 175 | 176 | end. 177 | -------------------------------------------------------------------------------- /plugins/source/cpp/pmm_rich/pmm_rich.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.3.32929.385 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pmm_rich", "source\pmm_rich.vcxproj", "{EA00E892-4D51-4D90-BA4F-1C540E07167B}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x64 = Debug|x64 11 | Debug|x86 = Debug|x86 12 | Release|x64 = Release|x64 13 | Release|x86 = Release|x86 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {EA00E892-4D51-4D90-BA4F-1C540E07167B}.Debug|x64.ActiveCfg = Debug|x64 17 | {EA00E892-4D51-4D90-BA4F-1C540E07167B}.Debug|x64.Build.0 = Debug|x64 18 | {EA00E892-4D51-4D90-BA4F-1C540E07167B}.Debug|x86.ActiveCfg = Debug|Win32 19 | {EA00E892-4D51-4D90-BA4F-1C540E07167B}.Debug|x86.Build.0 = Debug|Win32 20 | {EA00E892-4D51-4D90-BA4F-1C540E07167B}.Release|x64.ActiveCfg = Release|x64 21 | {EA00E892-4D51-4D90-BA4F-1C540E07167B}.Release|x64.Build.0 = Release|x64 22 | {EA00E892-4D51-4D90-BA4F-1C540E07167B}.Release|x86.ActiveCfg = Release|Win32 23 | {EA00E892-4D51-4D90-BA4F-1C540E07167B}.Release|x86.Build.0 = Release|Win32 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {33B769B5-62D5-4DFF-A40C-67D3561136CD} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /plugins/source/cpp/pmm_rich/source/RichParser.h: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // **************************************************************************** 4 | // * Project : ProcessMM 5 | // * Unit Name : RichParser.h 6 | // * Purpose : Заголовки классов для парсинга Rich заголовков 7 | // * Author : Александр (Rouse_) Багель 8 | // * Copyright : © Fangorn Wizards Lab 1998 - 2022. 9 | // * Version : 1.0 10 | // * Home Page : http://rouse.drkb.ru 11 | // * Home Blog : http://alexander-bagel.blogspot.ru 12 | // **************************************************************************** 13 | // * Stable Release : http://rouse.drkb.ru/winapi.php#pmm2 14 | // * Latest Source : https://github.com/AlexanderBagel/ProcessMemoryMap 15 | // **************************************************************************** 16 | // 17 | 18 | #pragma once 19 | 20 | #include 21 | #include 22 | #include 23 | 24 | // типы данных в том порядке в каком они обычно идут в заголовке 25 | enum RichItemType 26 | { 27 | ritDosStub, // 16-битный DOS стаб 28 | ritBeginProdId, // начало списка идентификаторов с контрольной суммой 29 | ritObject, // идентификаторы продуктов со счетчиками 30 | ritEndProdId, // конец списка идентификаторов с XOR ключем 31 | ritNull // пустые элементы для выравнивания 32 | }; 33 | 34 | struct ProdItem 35 | { 36 | ULONG64 addrVA; 37 | DWORD size; 38 | DWORD prodID; // Product identity 39 | DWORD count; // Count of objects built with that product 40 | RichItemType itemType; 41 | }; 42 | 43 | class PeRichSignReader 44 | { 45 | public: 46 | void Load(const wchar_t *filePath, ULONG64 hInst); 47 | 48 | std::vector Items(); 49 | BOOL Valid(); 50 | 51 | private: 52 | static const int tagBegID = 0x68636952; 53 | static const int tagEndID = 0x536E6144; 54 | BOOL valid_ = FALSE; 55 | std::vector data_; 56 | }; 57 | 58 | class RichManager 59 | { 60 | public: 61 | struct DescriptorRawData 62 | { 63 | std::wstring nameSpace; 64 | std::wstring caption; 65 | std::wstring description; 66 | DWORD size = 0; 67 | }; 68 | 69 | void OpenProcess(struct ProcessModule *list); 70 | BOOL GetDescriptorData(int index, struct DescriptorRawData *data); 71 | 72 | std::vector Items(); 73 | 74 | private: 75 | std::wstring GetItemVersion(DWORD, DWORD); 76 | std::wstring GetItemDescription(DWORD); 77 | std::vector data_; 78 | }; -------------------------------------------------------------------------------- /plugins/source/cpp/pmm_rich/source/dllmain.cpp: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // **************************************************************************** 4 | // * Project : ProcessMM 5 | // * Unit Name : dllmain.cpp 6 | // * Purpose : Демонстрационный плагин для отображения Rich заголовков 7 | // * Author : Александр (Rouse_) Багель 8 | // * Copyright : © Fangorn Wizards Lab 1998 - 2023. 9 | // * Version : 1.0.1 10 | // * Home Page : http://rouse.drkb.ru 11 | // * Home Blog : http://alexander-bagel.blogspot.ru 12 | // **************************************************************************** 13 | // * Stable Release : http://rouse.drkb.ru/winapi.php#pmm2 14 | // * Latest Source : https://github.com/AlexanderBagel/ProcessMemoryMap 15 | // **************************************************************************** 16 | // 17 | 18 | #include 19 | #include "RichParser.h" 20 | #include "ext.h" 21 | 22 | /* 23 | * 24 | * Общая задача плагина для РММ - генерация описаний для известных плагину адресов. 25 | * При старте плагин должен вернуть структуру Plugin в которой хосту будут 26 | * переданы параметры плагина и адреса гейтов, через которые будет работать хост. 27 | * их всего пять : 28 | * 29 | * 1. Gate.Open - эта функция вызывается при открытии процесса хостом 30 | * На вход идет двусвязный список модулей открытого процесса и его PID 31 | * При вызове этой функции плагин долже выполнить инициализацию данных 32 | * 33 | * 2. Gate.Close - хост закрыл процесс, плагин может освободить все занятые данные. 34 | * 35 | * 3. Gate.DescriptorCount - хост запрашивает количество известных плагину дескрипторов 36 | * Весь обмен данными происходит посредством дескрипторов, представляющих из себя 37 | * структуру Descriptor из двух полей 38 | * AddrVA - адрес описываемый дескриптором 39 | * Handle - некий уникальный идентификатор известный плагину, на основе которого 40 | * хост будет запрашивать расширенную информацию при обработке адреса. 41 | * В текущем демонстрационном плагине в качестве значения Handle используется 42 | * индекс в списке известных плагину адресов, которые строятся из декодированых 43 | * и распарсеных Rich таблиц. 44 | * 45 | * 4. Gate.GetDescriptor - хост запрашивает дескриптор по индексу 46 | * 47 | * 5. Gate.GetDescriptorData - хост запрашивает расширеную информацию по дескриптору 48 | * именно эта расширеная информация и выводится хостом. 49 | * Информация отдается ввиде структуры DescriptorData состоящей 50 | * из одного обязательного поля - Caption, которое используется всегда, 51 | * что для вывода информации по структурам / таблицам и прочему в режиме Raw, 52 | * так и при выводе информации в режиме дизассеблера и трех не обязательных, 53 | * применяемых для вывода полей структур / таблиц(не используются в режиме дизассемблера) 54 | * А именно : 55 | * NameSpace - указывает наименование описываемой структуры или таблицы 56 | * Description - произвольный коментарий 57 | * Size - размер данных описанных в дескрипторе 58 | * 59 | */ 60 | 61 | const DWORD PluginID = 0x72696368; // "rich" 62 | std::wstring PluginName = L"Rich Signarure Parser (MS VC++ demo plugin.)"; 63 | std::wstring PluginAuthor = L"Alexander (Rouse_) Bagel"; 64 | std::wstring PluginHomePage = L"https://github.com/AlexanderBagel/ProcessMemoryMap/tree/master/plugins/source/cpp/pmm_rich/"; 65 | std::wstring PluginDescription = L"The plugin decodes the Rich structure in an executable file " \ 66 | "(after the DOS-header) and displays information about known fields."; 67 | 68 | RichManager *rich; 69 | 70 | DWORD WINAPI PluginOpenProcess(DWORD processID, struct ProcessModule *list) 71 | { 72 | if (!list) 73 | return ERROR_INVALID_PARAMETER; 74 | 75 | try 76 | { 77 | rich = new RichManager; 78 | rich->OpenProcess(list); 79 | 80 | return NO_ERROR; 81 | } 82 | catch (...) 83 | { 84 | return ERROR_INVALID_DATA; 85 | } 86 | } 87 | 88 | void WINAPI PluginCloseProcess() 89 | { 90 | if (rich) 91 | { 92 | delete rich; 93 | rich = NULL; 94 | } 95 | return; 96 | } 97 | 98 | int WINAPI PluginDescriptorCount() 99 | { 100 | if (rich) 101 | { 102 | return (int)rich->Items().size(); 103 | } 104 | return 0; 105 | } 106 | 107 | DWORD WINAPI PluginGetDescriptor(int index, struct Descriptor *pDesc) 108 | { 109 | if (!rich) 110 | return ERROR_DLL_INIT_FAILED; 111 | if ((index < 0) || (index >= rich->Items().size())) 112 | return ERROR_INVALID_PARAMETER; 113 | if (IsBadWritePtr(pDesc, sizeof(Descriptor))) 114 | return ERROR_INVALID_PARAMETER; 115 | pDesc->AddrVA = rich->Items()[(int)index].addrVA; 116 | pDesc->Handle = (HANDLE)(INT_PTR)index; 117 | pDesc->DescrType = PMM_DESCR_TYPE_STRUCT; 118 | return NO_ERROR; 119 | } 120 | 121 | DWORD WINAPI PluginGetDescriptorData(HANDLE index, struct DescriptorData *pDesc, UINT32 *nSize) 122 | { 123 | if (!rich) 124 | return ERROR_DLL_INIT_FAILED; 125 | 126 | if (IsBadReadPtr(nSize, 4)) 127 | return ERROR_INVALID_PARAMETER; 128 | if (IsBadWritePtr(nSize, 4)) 129 | return ERROR_INVALID_PARAMETER; 130 | 131 | RichManager::DescriptorRawData data; 132 | if (!rich->GetDescriptorData((int)(INT_PTR)index, &data)) 133 | return ERROR_INVALID_PARAMETER; 134 | 135 | UINT32 size = 136 | (UINT32)(sizeof(DescriptorData) + 137 | (data.caption.length() + 1) * sizeof(wchar_t) + 138 | (data.description.length() + 1) * sizeof(wchar_t) + 139 | (data.nameSpace.length() + 1) * sizeof(wchar_t)); 140 | 141 | if ((!pDesc) || (*nSize < size)) 142 | { 143 | *nSize = size; 144 | return ERROR_INSUFFICIENT_BUFFER; 145 | } 146 | 147 | if (IsBadWritePtr(pDesc, size)) 148 | return ERROR_INVALID_PARAMETER; 149 | 150 | ZeroMemory(pDesc, size); 151 | size = sizeof(DescriptorData); 152 | pDesc->NameSpace = (wchar_t*)((ULONG64)pDesc + size); 153 | size = (UINT32)((data.nameSpace.length() + 1) * sizeof(wchar_t)); 154 | if (size) 155 | { 156 | memcpy(pDesc->NameSpace, data.nameSpace.c_str(), size); 157 | } 158 | pDesc->Caption = (wchar_t*)((ULONG64)pDesc->NameSpace + size); 159 | size = (UINT32)((data.caption.length() + 1) * sizeof(wchar_t)); 160 | if (size) 161 | { 162 | memcpy(pDesc->Caption, data.caption.c_str(), size); 163 | } 164 | pDesc->Description = (wchar_t*)((ULONG64)pDesc->Caption + size); 165 | size = (UINT32)((data.description.length() + 1) * sizeof(wchar_t)); 166 | if (size) 167 | { 168 | memcpy(pDesc->Description, data.description.c_str(), size); 169 | } 170 | pDesc->Size = data.size; 171 | return NO_ERROR; 172 | } 173 | 174 | __declspec(dllexport) struct Plugin WINAPI pmm_get_plugin_info() 175 | { 176 | Plugin plugin_info = {}; 177 | plugin_info.VersionApi = PMM_API_VER; 178 | plugin_info.PluginUID = PluginID; 179 | 180 | plugin_info.Gate.PluginOpenProcess = PluginOpenProcess; 181 | plugin_info.Gate.PluginCloseProcess = PluginCloseProcess; 182 | plugin_info.Gate.PluginDescriptorCount = PluginDescriptorCount; 183 | plugin_info.Gate.PluginGetDescriptor = PluginGetDescriptor; 184 | plugin_info.Gate.PluginGetDescriptorData = PluginGetDescriptorData; 185 | 186 | plugin_info.PluginName = PluginName.c_str(); 187 | plugin_info.PluginAuthor = PluginAuthor.c_str(); 188 | plugin_info.PluginHomePage = PluginHomePage.c_str(); 189 | plugin_info.PluginDescription = PluginDescription.c_str(); 190 | 191 | return plugin_info; 192 | } 193 | 194 | BOOL APIENTRY DllMain( HMODULE hModule, 195 | DWORD ul_reason_for_call, 196 | LPVOID lpReserved 197 | ) 198 | { 199 | switch (ul_reason_for_call) 200 | { 201 | case DLL_PROCESS_ATTACH: 202 | case DLL_THREAD_ATTACH: 203 | case DLL_THREAD_DETACH: 204 | case DLL_PROCESS_DETACH: 205 | break; 206 | } 207 | return TRUE; 208 | } -------------------------------------------------------------------------------- /plugins/source/cpp/pmm_rich/source/exports.def: -------------------------------------------------------------------------------- 1 | LIBRARY 2 | EXPORTS 3 | pmm_get_plugin_info=pmm_get_plugin_info -------------------------------------------------------------------------------- /plugins/source/cpp/pmm_rich/source/ext.h: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // **************************************************************************** 4 | // * Project : ProcessMM 5 | // * Unit Name : ext.h 6 | // * Purpose : Все внешние зависимости 7 | // * Author : Александр (Rouse_) Багель 8 | // * Copyright : © Fangorn Wizards Lab 1998 - 2022. 9 | // * Version : 1.0 10 | // * Home Page : http://rouse.drkb.ru 11 | // * Home Blog : http://alexander-bagel.blogspot.ru 12 | // **************************************************************************** 13 | // * Stable Release : http://rouse.drkb.ru/winapi.php#pmm2 14 | // * Latest Source : https://github.com/AlexanderBagel/ProcessMemoryMap 15 | // **************************************************************************** 16 | // 17 | 18 | #ifndef extH 19 | #define extH 20 | 21 | #pragma once 22 | 23 | #include "..\..\..\..\include\pmm_plugin.h" 24 | 25 | #endif // extH -------------------------------------------------------------------------------- /plugins/source/cpp/pmm_rich/source/pmm_rich.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Header Files 20 | 21 | 22 | Header Files 23 | 24 | 25 | Header Files 26 | 27 | 28 | 29 | 30 | Source Files 31 | 32 | 33 | Source Files 34 | 35 | 36 | 37 | 38 | Source Files 39 | 40 | 41 | -------------------------------------------------------------------------------- /plugins/source/cpp/pmm_rich/source/pmm_rich.vcxproj.user: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | $(ProjectDir)..\..\..\..\..\Win32\Release\ProcessMM.exe 5 | WindowsLocalDebugger 6 | x32 27992 $00540000 7 | 8 | 9 | $(ProjectDir)..\..\..\..\..\Win32\Release\ProcessMM.exe 10 | WindowsLocalDebugger 11 | 27992 $00540000 12 | 13 | -------------------------------------------------------------------------------- /plugins/source/delphi/pmm_rich/pmm_rich.dpr: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // **************************************************************************** 4 | // * Project : ProcessMM 5 | // * Unit Name : pmm_rich.dpr 6 | // * Purpose : Демонстрационный плагин для отображения Rich заголовков 7 | // * Author : Александр (Rouse_) Багель 8 | // * Copyright : © Fangorn Wizards Lab 1998 - 2023. 9 | // * Version : 1.0.1 10 | // * Home Page : http://rouse.drkb.ru 11 | // * Home Blog : http://alexander-bagel.blogspot.ru 12 | // **************************************************************************** 13 | // * Stable Release : http://rouse.drkb.ru/winapi.php#pmm2 14 | // * Latest Source : https://github.com/AlexanderBagel/ProcessMemoryMap 15 | // **************************************************************************** 16 | // 17 | 18 | library pmm_rich; 19 | 20 | uses 21 | Windows, 22 | System.SysUtils, 23 | System.Classes, 24 | pmm_plugin in '..\..\..\include\pmm_plugin.pas', 25 | uRichParser in 'uRichParser.pas'; 26 | 27 | {$R *.res} 28 | 29 | { 30 | Общая задача плагина для РММ - генерация описаний для известных плагину адресов. 31 | При старте плагин должен вернуть структуру TPlugin в которой хосту будут 32 | переданы параметры плагина и адреса гейтов, через которые будет работать хост. 33 | их всего пять: 34 | 35 | 1. Gate.Open - эта функция вызывается при открытии процесса хостом 36 | На вход идет двусвязный список модулей открытого процесса и его PID 37 | При вызове этой функции плагин долже выполнить инициализацию данных 38 | 39 | 2. Gate.Close - хост закрыл процесс, плагин может освободить все занятые данные. 40 | 41 | 3. Gate.DescriptorCount - хост запрашивает количество известных плагину дескрипторов 42 | Весь обмен данными происходит посредством дескрипторов, представляющих из себя 43 | структуру TDescriptor из двух полей 44 | AddrVA - адрес описываемый дескриптором 45 | Handle - некий уникальный идентификатор известный плагину, на основе которого 46 | хост будет запрашивать расширенную информацию при обработке адреса. 47 | В текущем демонстрационном плагине в качестве значения Handle используется 48 | индекс в списке известных плагину адресов, которые строятся из декодированых 49 | и распарсеных Rich таблиц. 50 | 51 | 4. Gate.GetDescriptor - хост запрашивает дескриптор по индексу 52 | 53 | 5. Gate.GetDescriptorData - хост запрашивает расширеную информацию по дескриптору 54 | именно эта расширеная информация и выводится хостом. 55 | Информация отдается ввиде структуры TDescriptorData состоящей 56 | из одного обязательного поля - Caption, которое используется всегда, 57 | что для вывода информации по структурам/таблицам и прочему в режиме Raw, 58 | так и при выводе информации в режиме дизассеблера и трех не обязательных, 59 | применяемых для вывода полей структур/таблиц (не используются в режиме дизассемблера) 60 | А именно: 61 | NameSpace - указывает наименование описываемой структуры или таблицы 62 | Description - произвольный коментарий 63 | Size - размер данных описанных в дескрипторе 64 | } 65 | 66 | const 67 | // уникальный UID плагина по которому он будет детектироваться без учета версий 68 | PluginUID = $72696368; // "rich" 69 | PluginName = 'Rich Signarure Parser (Delphi demo plugin)'; 70 | PluginAuthor = 'Alexander (Rouse_) Bagel'; 71 | PluginHomePage = 72 | 'https://github.com/AlexanderBagel/ProcessMemoryMap/tree/master/plugins/source/delphi/pmm_rich/'; 73 | PluginDesсription = 'The plugin decodes the Rich structure in an executable file ' + 74 | '(after the DOS-header) and displays information about known fields.'; 75 | 76 | var 77 | RichManager: TRichManager = nil; 78 | 79 | function PlgOpenProcess(AProcessID: DWORD; AModuleList: PProcessModule): DWORD; stdcall; 80 | begin 81 | Result := ERROR_INVALID_PARAMETER; 82 | if RichManager = nil then 83 | RichManager := TRichManager.Create; 84 | try 85 | if Assigned(AModuleList) then 86 | begin 87 | RichManager.OpenProcess(AModuleList); 88 | Result := NO_ERROR; 89 | end; 90 | except 91 | Result := ERROR_INVALID_DATA; 92 | end; 93 | end; 94 | 95 | procedure PlgCloseProcess; stdcall; 96 | begin 97 | FreeAndNil(RichManager); 98 | end; 99 | 100 | function PlgDescriptorCount: Integer; stdcall; 101 | begin 102 | if Assigned(RichManager) then 103 | Result := RichManager.Items.Count 104 | else 105 | Result := 0; 106 | end; 107 | 108 | function PlgGetDescriptor(Index: Integer; pDesc: PDescriptor): DWORD; stdcall; 109 | begin 110 | if RichManager = nil then 111 | Exit(ERROR_DLL_INIT_FAILED); 112 | if (Index < 0) or (Index >= PlgDescriptorCount) then 113 | Exit(ERROR_INVALID_PARAMETER); 114 | if IsBadWritePtr(pDesc, SizeOf(TDescriptor)) then 115 | Exit(ERROR_INVALID_PARAMETER); 116 | pDesc.AddrVA := RichManager.Items[Index].AddrVA; 117 | pDesc.Handle := Index; 118 | pDesc.DescrType := PMM_DESCR_TYPE_STRUCT; 119 | Result := NO_ERROR; 120 | end; 121 | 122 | function PlgGetDescriptorData(AHandle: THandle; 123 | pDescData: PDescriptorData; pSize: PInteger): DWORD; stdcall; 124 | var 125 | Data: TRawData; 126 | Size: Integer; 127 | begin 128 | if RichManager = nil then 129 | Exit(ERROR_DLL_INIT_FAILED); 130 | if IsBadReadPtr(pSize, 4) or IsBadWritePtr(pSize, 4) then 131 | Exit(ERROR_INVALID_PARAMETER); 132 | 133 | if not RichManager.GetDescriptorData(Integer(AHandle), Data) then 134 | Exit(ERROR_INVALID_PARAMETER); 135 | 136 | Size := 137 | SizeOf(TDescriptorData) + 138 | Length(Data.NameSpace) shl 1 + 2 + 139 | Length(Data.Caption) shl 1 + 2 + 140 | Length(Data.Description) shl 1 + 2; 141 | if (pDescData = nil) or (pSize^ < Size) then 142 | begin 143 | pSize^ := Size; 144 | Exit(ERROR_INSUFFICIENT_BUFFER); 145 | end; 146 | if IsBadWritePtr(pDescData, Size) then 147 | Exit(ERROR_INVALID_PARAMETER); 148 | 149 | ZeroMemory(pDescData, Size); 150 | Size := SizeOf(TDescriptorData); 151 | pDescData.NameSpace := PChar(PByte(pDescData) + Size); 152 | Size := Length(Data.NameSpace) shl 1 + 2; 153 | pDescData.Caption := PChar(PByte(pDescData.NameSpace) + Size); 154 | Size := Length(Data.Caption) shl 1 + 2; 155 | pDescData.Description := PChar(PByte(pDescData.Caption) + Size); 156 | pDescData.Size := Data.Size; 157 | if Data.NameSpace <> EmptyStr then 158 | Move(Data.NameSpace[1], pDescData.NameSpace^, Length(Data.NameSpace) shl 1); 159 | if Data.Caption <> EmptyStr then 160 | Move(Data.Caption[1], pDescData.Caption^, Length(Data.Caption) shl 1); 161 | if Data.Description <> EmptyStr then 162 | Move(Data.Description[1], pDescData.Description^, Length(Data.Description) shl 1); 163 | Result := NO_ERROR; 164 | end; 165 | 166 | function pmm_get_plugin_info: TPlugin; stdcall; 167 | begin 168 | ZeroMemory(@Result, SizeOf(TPlugin)); 169 | Result.VersionApi := PMM_API_VER; 170 | Result.PluginUID := PluginUID; 171 | Result.Gate.Open := PlgOpenProcess; 172 | Result.Gate.Close := PlgCloseProcess; 173 | Result.Gate.DescriptorCount := PlgDescriptorCount; 174 | Result.Gate.GetDescriptor := PlgGetDescriptor; 175 | Result.Gate.GetDescriptorData := PlgGetDescriptorData; 176 | Result.PluginName := @PluginName[1]; 177 | Result.PluginAuthor := @PluginAuthor[1]; 178 | Result.PluginHomePage := @PluginHomePage[1]; 179 | Result.PluginDesсription := @PluginDesсription[1]; 180 | end; 181 | 182 | exports 183 | pmm_get_plugin_info; 184 | 185 | begin 186 | end. 187 | -------------------------------------------------------------------------------- /plugins/source/delphi/pmm_rich/pmm_rich.res: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexanderBagel/ProcessMemoryMap/c5dc46ff63fb0fa20f6728abed0214786f91e4a2/plugins/source/delphi/pmm_rich/pmm_rich.res -------------------------------------------------------------------------------- /plugins/source/dwarfreader/README.md: -------------------------------------------------------------------------------- 1 | DWARF Reader 2 | ================ 3 | 4 | Небольшая утилита выводящая информацию об присутствующей отладочной информации в исполняемом файле. 5 | Поддерживаются форматы: 6 | * PE32/64 - выводится DWARF информация и информация из COFF секции (Va+Raw адресация) 7 | * ELF32/64 - выводится DWARF информация и информация из секции символов (Va+Raw адресация), для обьектных файлов данные выводятся только в Raw адресации. 8 | * обьектные COFF32/64 - выводится DWARF информация и информация из COFF секции. Доступна только Raw адресация. 9 | 10 | ВАЖНО: 11 | Обьектные файлы содержат DWARF информацию без указания адресов, поэтому для них она выводится только как информационная. 12 | Частично ввиде Raw оффсетов информация присутствует в секции символов (для ELF обьектников) и в секции COFF. 13 | 14 | ###Внешний вид: 15 | 16 | ![1](https://github.com/AlexanderBagel/ProcessMemoryMap/blob/master/plugins/source/dwarfreader/img/1.png?raw=true "Внешний вид") -------------------------------------------------------------------------------- /plugins/source/dwarfreader/img/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexanderBagel/ProcessMemoryMap/c5dc46ff63fb0fa20f6728abed0214786f91e4a2/plugins/source/dwarfreader/img/1.png -------------------------------------------------------------------------------- /src/gui/uAbout.pas: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // **************************************************************************** 4 | // * Project : ProcessMM 5 | // * Unit Name : uAbout.pas 6 | // * Purpose : Диалог "О программе" 7 | // * Author : Александр (Rouse_) Багель 8 | // * Copyright : © Fangorn Wizards Lab 1998 - 2025. 9 | // * Version : 1.5.46 10 | // * Home Page : http://rouse.drkb.ru 11 | // * Home Blog : http://alexander-bagel.blogspot.ru 12 | // **************************************************************************** 13 | // * Stable Release : http://rouse.drkb.ru/winapi.php#pmm2 14 | // * Latest Source : https://github.com/AlexanderBagel/ProcessMemoryMap 15 | // **************************************************************************** 16 | // 17 | 18 | unit uAbout; 19 | 20 | interface 21 | 22 | uses 23 | Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, 24 | System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, 25 | Vcl.ExtCtrls, Vcl.StdCtrls, Winapi.ShellAPI; 26 | 27 | type 28 | TdlgAbout = class(TForm) 29 | Image1: TImage; 30 | lblPMMVer: TLabel; 31 | Label2: TLabel; 32 | LinkLabel3: TLinkLabel; 33 | Button1: TButton; 34 | Label3: TLabel; 35 | LinkLabel4: TLinkLabel; 36 | lblDistorm: TLinkLabel; 37 | LinkLabel1: TLinkLabel; 38 | lblMMVer: TLabel; 39 | lblRawVer: TLabel; 40 | Label1: TLabel; 41 | lblZipVer: TLinkLabel; 42 | procedure LinkLabel1LinkClick(Sender: TObject; const Link: string; 43 | LinkType: TSysLinkType); 44 | procedure FormCreate(Sender: TObject); 45 | private 46 | { Private declarations } 47 | public 48 | { Public declarations } 49 | end; 50 | 51 | var 52 | dlgAbout: TdlgAbout; 53 | 54 | implementation 55 | 56 | uses 57 | MemoryMap.Core, 58 | RawScanner.Core, 59 | FWZipConsts, 60 | distorm; 61 | 62 | {$R *.dfm} 63 | 64 | procedure TdlgAbout.FormCreate(Sender: TObject); 65 | const 66 | VFF_PRERELEASE = 2; 67 | var 68 | dwVer: DWORD; 69 | VerInfoSize, Dummy: DWORD; 70 | PVerBbuff, PFixed: Pointer; 71 | FixLength: UINT; 72 | VerLoaded: Boolean; 73 | BetaMark: string; 74 | begin 75 | VerInfoSize := GetFileVersionInfoSize(PChar(ParamStr(0)), Dummy); 76 | VerLoaded := False; 77 | if VerInfoSize > 0 then 78 | begin 79 | GetMem(PVerBbuff, VerInfoSize); 80 | try 81 | if GetFileVersionInfo(PChar(ParamStr(0)), 0, VerInfoSize, PVerBbuff) then 82 | begin 83 | if VerQueryValue(PVerBbuff, '\', PFixed, FixLength) then 84 | begin 85 | if PVSFixedFileInfo(PFixed)^.dwFileFlags and VFF_PRERELEASE <> 0 then 86 | BetaMark := ' (Beta)' 87 | else 88 | BetaMark := ''; 89 | lblPMMVer.Caption := Format('Process Memory Map: %d.%d.%d.%d%s', [ 90 | PVSFixedFileInfo(PFixed)^.dwFileVersionMS shr 16, 91 | PVSFixedFileInfo(PFixed)^.dwFileVersionMS and $FFFF, 92 | PVSFixedFileInfo(PFixed)^.dwFileVersionLS shr 16, 93 | PVSFixedFileInfo(PFixed)^.dwFileVersionLS and $FFFF, 94 | BetaMark]); 95 | VerLoaded := True; 96 | end; 97 | end; 98 | finally 99 | FreeMem(PVerBbuff); 100 | end; 101 | end; 102 | 103 | if not VerLoaded then 104 | lblPMMVer.Caption := 'Process Memory Map ' + MemoryMapVersionStr; 105 | 106 | dwVer := get_distorm_version; 107 | lblDistorm.Caption := 108 | Format( 109 | 'Disasm engine: ' + 110 | 'diStorm version %d.%d.%d', 111 | [dwVer shr 16, Byte(dwVer shr 8), Byte(dwVer)]); 112 | 113 | dwVer := MemoryMapVersionInt; 114 | lblMMVer.Caption := Format( 115 | 'MemoryMap Core: version %d.%d (revision %d)', 116 | [dwVer shr 24, Byte(dwVer shr 16), Word(dwVer)]); 117 | 118 | dwVer := RawScannerVersionInt; 119 | lblRawVer.Caption := Format( 120 | 'RawScanner Core: version %d.%d (revision %d)', 121 | [dwVer shr 24, Byte(dwVer shr 16), Word(dwVer)]); 122 | 123 | dwVer := FWZipVersionInt; 124 | lblZipVer.Caption := Format( 125 | 'Compression Library: ' + 126 | 'FWZip version %d.%d.%d', 127 | [dwVer shr 24, Byte(dwVer shr 16), Word(dwVer)]); 128 | end; 129 | 130 | procedure TdlgAbout.LinkLabel1LinkClick(Sender: TObject; const Link: string; 131 | LinkType: TSysLinkType); 132 | begin 133 | ShellExecute(Handle, 'open', PChar(Link), nil, nil, SW_SHOWNORMAL); 134 | end; 135 | 136 | end. 137 | -------------------------------------------------------------------------------- /src/gui/uBaseForm.dfm: -------------------------------------------------------------------------------- 1 | object BaseAppForm: TBaseAppForm 2 | Left = 0 3 | Top = 0 4 | Caption = 'BaseAppForm' 5 | ClientHeight = 411 6 | ClientWidth = 852 7 | Color = clBtnFace 8 | Font.Charset = DEFAULT_CHARSET 9 | Font.Color = clWindowText 10 | Font.Height = -11 11 | Font.Name = 'Tahoma' 12 | Font.Style = [] 13 | OldCreateOrder = False 14 | PixelsPerInch = 96 15 | TextHeight = 13 16 | end 17 | -------------------------------------------------------------------------------- /src/gui/uBaseForm.pas: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // **************************************************************************** 4 | // * Project : ProcessMM 5 | // * Unit Name : uBaseForm.pas 6 | // * Purpose : Базовая форма от которой наследуются все дочерние 7 | // * Author : Александр (Rouse_) Багель 8 | // * Copyright : © Fangorn Wizards Lab 1998 - 2023. 9 | // * Version : 1.4.30 10 | // * Home Page : http://rouse.drkb.ru 11 | // * Home Blog : http://alexander-bagel.blogspot.ru 12 | // **************************************************************************** 13 | // * Stable Release : http://rouse.drkb.ru/winapi.php#pmm2 14 | // * Latest Source : https://github.com/AlexanderBagel/ProcessMemoryMap 15 | // **************************************************************************** 16 | // 17 | 18 | unit uBaseForm; 19 | 20 | interface 21 | 22 | uses 23 | Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, 24 | System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs; 25 | 26 | type 27 | TBaseAppForm = class(TForm) 28 | protected 29 | procedure CreateParams(var Params: TCreateParams); override; 30 | end; 31 | 32 | var 33 | BaseAppForm: TBaseAppForm; 34 | 35 | implementation 36 | 37 | uses 38 | uSettings; 39 | 40 | {$R *.dfm} 41 | 42 | procedure TBaseAppForm.CreateParams(var Params: TCreateParams); 43 | begin 44 | inherited; 45 | if Settings.ShowChildFormsOnTaskBar then 46 | begin 47 | Params.ExStyle := Params.ExStyle or WS_EX_APPWINDOW; 48 | Params.WndParent := 0; 49 | end; 50 | end; 51 | 52 | end. 53 | -------------------------------------------------------------------------------- /src/gui/uComparator.dfm: -------------------------------------------------------------------------------- 1 | object dlgComparator: TdlgComparator 2 | Left = 0 3 | Top = 0 4 | Caption = 'Process Memory Map - Compare Result' 5 | ClientHeight = 528 6 | ClientWidth = 786 7 | Color = clBtnFace 8 | Font.Charset = DEFAULT_CHARSET 9 | Font.Color = clWindowText 10 | Font.Height = -11 11 | Font.Name = 'Tahoma' 12 | Font.Style = [] 13 | OldCreateOrder = False 14 | Position = poMainFormCenter 15 | PixelsPerInch = 96 16 | TextHeight = 13 17 | object Panel1: TPanel 18 | Left = 0 19 | Top = 487 20 | Width = 786 21 | Height = 41 22 | Align = alBottom 23 | BevelOuter = bvNone 24 | TabOrder = 0 25 | DesignSize = ( 26 | 786 27 | 41) 28 | object Button1: TButton 29 | Left = 704 30 | Top = 6 31 | Width = 75 32 | Height = 25 33 | Anchors = [akTop, akRight] 34 | Cancel = True 35 | Caption = 'Cancel' 36 | ModalResult = 2 37 | TabOrder = 0 38 | end 39 | object btnSave: TButton 40 | Left = 623 41 | Top = 6 42 | Width = 75 43 | Height = 25 44 | Anchors = [akTop, akRight] 45 | Caption = 'Save' 46 | Default = True 47 | TabOrder = 1 48 | OnClick = btnSaveClick 49 | end 50 | end 51 | object edChanges: TRichEdit 52 | Left = 0 53 | Top = 0 54 | Width = 786 55 | Height = 487 56 | Align = alClient 57 | Font.Charset = RUSSIAN_CHARSET 58 | Font.Color = clWindowText 59 | Font.Height = -11 60 | Font.Name = 'Tahoma' 61 | Font.Style = [] 62 | Lines.Strings = ( 63 | 'edChanges') 64 | ParentFont = False 65 | PopupMenu = PopupMenu 66 | ReadOnly = True 67 | ScrollBars = ssBoth 68 | TabOrder = 1 69 | Zoom = 100 70 | end 71 | object SaveDialog: TSaveDialog 72 | DefaultExt = 'rtf' 73 | Filter = 'Report (*.rtf)|*.rtf|All files (*.*)|*.*' 74 | Left = 24 75 | Top = 32 76 | end 77 | object PopupMenu: TPopupMenu 78 | Left = 104 79 | Top = 32 80 | object mnuCopy: TMenuItem 81 | Caption = 'Copy' 82 | ShortCut = 16451 83 | OnClick = mnuCopyClick 84 | end 85 | object SelectAll1: TMenuItem 86 | Caption = 'Select All' 87 | ShortCut = 16449 88 | OnClick = SelectAll1Click 89 | end 90 | end 91 | end 92 | -------------------------------------------------------------------------------- /src/gui/uDebugInfoDlg.dfm: -------------------------------------------------------------------------------- 1 | object dlgDbgInfo: TdlgDbgInfo 2 | Left = 0 3 | Top = 0 4 | Caption = 'Process Memory Map - Debug Info' 5 | ClientHeight = 417 6 | ClientWidth = 793 7 | Color = clBtnFace 8 | Font.Charset = DEFAULT_CHARSET 9 | Font.Color = clWindowText 10 | Font.Height = -11 11 | Font.Name = 'Tahoma' 12 | Font.Style = [] 13 | KeyPreview = True 14 | OldCreateOrder = False 15 | Position = poMainFormCenter 16 | OnKeyPress = FormKeyPress 17 | PixelsPerInch = 96 18 | TextHeight = 13 19 | object edDebugInfo: TRichEdit 20 | Left = 0 21 | Top = 0 22 | Width = 793 23 | Height = 417 24 | Align = alClient 25 | Font.Charset = RUSSIAN_CHARSET 26 | Font.Color = clWindowText 27 | Font.Height = -11 28 | Font.Name = 'Tahoma' 29 | Font.Style = [] 30 | ParentFont = False 31 | PopupMenu = PopupMenu1 32 | ReadOnly = True 33 | ScrollBars = ssBoth 34 | TabOrder = 0 35 | Zoom = 100 36 | end 37 | object PopupMenu1: TPopupMenu 38 | Left = 272 39 | Top = 96 40 | object Copyselected1: TMenuItem 41 | Caption = 'Copy selected' 42 | OnClick = Copyselected1Click 43 | end 44 | object Copydebuginfointoclipboard1: TMenuItem 45 | Caption = 'Copy debug info into clipboard' 46 | OnClick = Copydebuginfointoclipboard1Click 47 | end 48 | end 49 | end 50 | -------------------------------------------------------------------------------- /src/gui/uDebugInfoDlg.pas: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // **************************************************************************** 4 | // * Project : ProcessMM 5 | // * Unit Name : uDebugInfoDlg.pas 6 | // * Purpose : Краткая отладочная информация об открытом проекте 7 | // * Author : Александр (Rouse_) Багель 8 | // * Copyright : © Fangorn Wizards Lab 1998 - 2016, 2023. 9 | // * Version : 1.4.30 10 | // * Home Page : http://rouse.drkb.ru 11 | // * Home Blog : http://alexander-bagel.blogspot.ru 12 | // **************************************************************************** 13 | // * Stable Release : http://rouse.drkb.ru/winapi.php#pmm2 14 | // * Latest Source : https://github.com/AlexanderBagel/ProcessMemoryMap 15 | // **************************************************************************** 16 | // 17 | 18 | unit uDebugInfoDlg; 19 | 20 | interface 21 | 22 | uses 23 | Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, 24 | Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.ComCtrls, Vcl.Menus, 25 | Winapi.ShLwApi, 26 | 27 | ScaledCtrls; 28 | 29 | type 30 | TdlgDbgInfo = class(TForm) 31 | edDebugInfo: TRichEdit; 32 | PopupMenu1: TPopupMenu; 33 | Copydebuginfointoclipboard1: TMenuItem; 34 | Copyselected1: TMenuItem; 35 | procedure Copydebuginfointoclipboard1Click(Sender: TObject); 36 | procedure Copyselected1Click(Sender: TObject); 37 | procedure FormKeyPress(Sender: TObject; var Key: Char); 38 | private 39 | { Private declarations } 40 | public 41 | procedure ShowDebugInfo(Advanced: TStringList); 42 | end; 43 | 44 | var 45 | dlgDbgInfo: TdlgDbgInfo; 46 | 47 | implementation 48 | 49 | uses 50 | Clipbrd, 51 | MemoryMap.Core, 52 | RawScanner.SymbolStorage, 53 | uPluginManager, 54 | uSettings, 55 | uUtils; 56 | 57 | {$R *.dfm} 58 | 59 | { TdlgDbgInfo } 60 | 61 | procedure TdlgDbgInfo.Copydebuginfointoclipboard1Click(Sender: TObject); 62 | begin 63 | Clipboard.AsText := edDebugInfo.Text; 64 | end; 65 | 66 | procedure TdlgDbgInfo.Copyselected1Click(Sender: TObject); 67 | begin 68 | edDebugInfo.CopyToClipboard; 69 | end; 70 | 71 | procedure TdlgDbgInfo.FormKeyPress(Sender: TObject; var Key: Char); 72 | begin 73 | if Key = #27 then Close; 74 | end; 75 | 76 | procedure TdlgDbgInfo.ShowDebugInfo(Advanced: TStringList); 77 | var 78 | Tmp: string; 79 | I: Integer; 80 | begin 81 | if MemoryMapCore.PID <> 0 then 82 | begin 83 | if MemoryMapCore.Process64 then 84 | Tmp := ' (x64)' 85 | else 86 | Tmp := ' (x86)'; 87 | edDebugInfo.Lines.Add('PID: ' + IntToStr(MemoryMapCore.PID) + Tmp); 88 | edDebugInfo.Lines.Add('Name: ' + MemoryMapCore.ProcessName); 89 | edDebugInfo.Lines.Add('Path: ' + MemoryMapCore.ProcessPath); 90 | 91 | edDebugInfo.Lines.Add(EmptyStr); 92 | edDebugInfo.Lines.Add('Elapsed: ' + 93 | Format('%2.3f sec', [DebugElapsedMilliseconds / 1000])); 94 | SetLength(Tmp, 50); 95 | StrFormatByteSize(GetMemAlloc - DebugInitialHeapSize, @Tmp[1], 50); 96 | edDebugInfo.Lines.Add('Memory allocated: ' + PChar(Tmp)); 97 | 98 | edDebugInfo.Lines.Add(EmptyStr); 99 | edDebugInfo.Lines.Add('Symbols count: ' + 100 | Format('%.0n', [SymbolStorage.Count + 0.0])); 101 | edDebugInfo.Lines.Add('Symbols unique count: ' + 102 | Format('%.0n', [SymbolStorage.UniqueCount + 0.0])); 103 | edDebugInfo.Lines.Add('Duplicates: ' + 104 | Format('%.0n', [SymbolStorage.Count - SymbolStorage.UniqueCount + 0.0])); 105 | if Settings.LoadStrings or (SymbolStorage.StringsCount > 0) then 106 | edDebugInfo.Lines.Add('Strings: ' + 107 | Format('%.0n', [SymbolStorage.StringsCount + 0.0])) 108 | else 109 | edDebugInfo.Lines.Add('Strings: disabled in settings'); 110 | edDebugInfo.Lines.Add(EmptyStr); 111 | if MemoryMapCore.DebugMapData.LoadedMap.Count > 0 then 112 | begin 113 | edDebugInfo.Lines.Add('Loaded MAP files:'); 114 | for I := 0 to MemoryMapCore.DebugMapData.LoadedMap.Count - 1 do 115 | edDebugInfo.Lines.Add(Format('%d: %s', [I + 1, 116 | MemoryMapCore.DebugMapData.LoadedMap[I]])); 117 | edDebugInfo.Lines.Add(EmptyStr); 118 | edDebugInfo.Lines.Add('Function count: ' + 119 | Format('%.0n', [MemoryMapCore.DebugMapData.Items.Count + 0.0])); 120 | if MemoryMapCore.DebugMapData.Units.Count > 0 then 121 | begin 122 | edDebugInfo.Lines.Add('Units count: ' + 123 | Format('%.0n', [MemoryMapCore.DebugMapData.Units.Count + 0.0])); 124 | edDebugInfo.Lines.Add('Lines count: ' + 125 | Format('%.0n', [MemoryMapCore.DebugMapData.Lines.Count + 0.0])); 126 | end; 127 | edDebugInfo.Lines.Add(EmptyStr); 128 | end; 129 | if PluginManager.Items.Count > 0 then 130 | begin 131 | edDebugInfo.Lines.Add('Plugins:'); 132 | edDebugInfo.Lines.Add(EmptyStr); 133 | for var Plugin in PluginManager.Items do 134 | begin 135 | edDebugInfo.Lines.Add('Name: ' + Plugin.Name + ', UID: ' + IntToHex(Plugin.UID, 1)); 136 | edDebugInfo.Lines.Add('Author: ' + Plugin.Author); 137 | edDebugInfo.Lines.Add('Page: ' + Plugin.Page); 138 | edDebugInfo.Lines.Add('Description: ' + Plugin.Description); 139 | if Assigned(Plugin.Gate.DescriptorCount) then 140 | try 141 | edDebugInfo.Lines.Add(EmptyStr); 142 | edDebugInfo.Lines.Add('Descriptors count: ' + 143 | Format('%.0n', [Plugin.Gate.DescriptorCount + 0.0])); 144 | except 145 | on E: Exception do 146 | begin 147 | edDebugInfo.Lines.Add('Error get descriptors count'); 148 | edDebugInfo.Lines.Add(E.ClassName + ': ' + E.Message); 149 | end; 150 | end; 151 | edDebugInfo.Lines.Add(EmptyStr); 152 | end; 153 | end; 154 | end; 155 | 156 | if Advanced.Count > 0 then 157 | begin 158 | edDebugInfo.Lines.Add('Debug Log: '); 159 | for I := 0 to Advanced.Count - 1 do 160 | edDebugInfo.Lines.Add(Advanced[I]); 161 | end; 162 | 163 | ShowModal; 164 | end; 165 | 166 | end. 167 | -------------------------------------------------------------------------------- /src/gui/uExportList.dfm: -------------------------------------------------------------------------------- 1 | object dlgExportList: TdlgExportList 2 | Left = 0 3 | Top = 0 4 | ActiveControl = lvExports 5 | Caption = 'Process Memory Map - Exports' 6 | ClientHeight = 337 7 | ClientWidth = 704 8 | Color = clBtnFace 9 | Font.Charset = DEFAULT_CHARSET 10 | Font.Color = clWindowText 11 | Font.Height = -11 12 | Font.Name = 'Tahoma' 13 | Font.Style = [] 14 | KeyPreview = True 15 | OldCreateOrder = False 16 | Position = poMainFormCenter 17 | OnClose = FormClose 18 | OnCreate = FormCreate 19 | OnDestroy = FormDestroy 20 | OnKeyPress = FormKeyPress 21 | OnShow = FormShow 22 | PixelsPerInch = 96 23 | TextHeight = 13 24 | object lvExports: TVirtualStringTree 25 | Left = 0 26 | Top = 0 27 | Width = 704 28 | Height = 337 29 | Align = alClient 30 | Header.AutoSizeIndex = 3 31 | Header.Height = 17 32 | Header.Options = [hoAutoResize, hoColumnResize, hoDrag, hoShowSortGlyphs, hoVisible] 33 | PopupMenu = pmCopy 34 | TabOrder = 0 35 | TreeOptions.PaintOptions = [toHideFocusRect, toShowButtons, toShowDropmark, toShowRoot, toShowVertGridLines, toThemeAware, toUseBlendedImages, toUseBlendedSelection, toUseExplorerTheme] 36 | TreeOptions.SelectionOptions = [toFullRowSelect] 37 | OnBeforeItemErase = lvExportsBeforeItemErase 38 | OnDblClick = lvExportsDblClick 39 | OnGetText = lvExportsGetText 40 | OnHeaderClick = lvExportsHeaderClick 41 | Touch.InteractiveGestures = [igPan, igPressAndTap] 42 | Touch.InteractiveGestureOptions = [igoPanSingleFingerHorizontal, igoPanSingleFingerVertical, igoPanInertia, igoPanGutter, igoParentPassthrough] 43 | Columns = < 44 | item 45 | Position = 0 46 | Text = 'Type' 47 | Width = 118 48 | end 49 | item 50 | Position = 1 51 | Text = 'Address' 52 | Width = 150 53 | end 54 | item 55 | Position = 2 56 | Text = 'Module' 57 | Width = 136 58 | end 59 | item 60 | Options = [coAllowClick, coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coShowDropMark, coVisible, coAutoSpring, coAllowFocus] 61 | Position = 3 62 | Text = 'Function' 63 | Width = 296 64 | end> 65 | end 66 | object pmCopy: TPopupMenu 67 | Left = 32 68 | Top = 32 69 | object mnuGotoAddress: TMenuItem 70 | Caption = 'Go to Address' 71 | Default = True 72 | ShortCut = 13 73 | OnClick = mnuGotoAddressClick 74 | end 75 | object mnuSeparator1: TMenuItem 76 | Caption = '-' 77 | end 78 | object mnuCopyAddress: TMenuItem 79 | Caption = 'Copy Address' 80 | OnClick = mnuCopyAddressClick 81 | end 82 | object mnuCopyFunctionName: TMenuItem 83 | Caption = 'Copy Function Name' 84 | OnClick = mnuCopyFunctionNameClick 85 | end 86 | object mnuCopyLine: TMenuItem 87 | Caption = 'Copy Line' 88 | OnClick = mnuCopyLineClick 89 | end 90 | object mnuSeparator2: TMenuItem 91 | Caption = '-' 92 | end 93 | object mnuNextMatch: TMenuItem 94 | Caption = 'Next Match' 95 | ShortCut = 114 96 | OnClick = mnuNextMatchClick 97 | end 98 | end 99 | end 100 | -------------------------------------------------------------------------------- /src/gui/uFindData.dfm: -------------------------------------------------------------------------------- 1 | object dlgFindData: TdlgFindData 2 | Left = 0 3 | Top = 0 4 | BorderStyle = bsDialog 5 | Caption = 'Process Memory Map - Search Data' 6 | ClientHeight = 113 7 | ClientWidth = 489 8 | Color = clBtnFace 9 | Font.Charset = DEFAULT_CHARSET 10 | Font.Color = clWindowText 11 | Font.Height = -11 12 | Font.Name = 'Tahoma' 13 | Font.Style = [] 14 | OldCreateOrder = False 15 | Position = poMainFormCenter 16 | OnClose = FormClose 17 | OnCreate = FormCreate 18 | OnShow = FormShow 19 | PixelsPerInch = 96 20 | TextHeight = 13 21 | object Label1: TLabel 22 | Left = 16 23 | Top = 8 24 | Width = 28 25 | Height = 13 26 | Caption = 'Type:' 27 | end 28 | object Label2: TLabel 29 | Left = 16 30 | Top = 35 31 | Width = 26 32 | Height = 13 33 | Caption = 'Text:' 34 | end 35 | object Label4: TLabel 36 | Left = 16 37 | Top = 87 38 | Width = 58 39 | Height = 13 40 | Caption = 'Start (HEX):' 41 | end 42 | object btnCancel: TButton 43 | Left = 406 44 | Top = 82 45 | Width = 75 46 | Height = 25 47 | Cancel = True 48 | Caption = 'Cancel' 49 | TabOrder = 0 50 | OnClick = btnCancelClick 51 | end 52 | object btnSearch: TButton 53 | Left = 325 54 | Top = 82 55 | Width = 75 56 | Height = 25 57 | Caption = 'Search' 58 | Default = True 59 | TabOrder = 1 60 | OnClick = btnSearchClick 61 | end 62 | object cbSkipROMem: TCheckBox 63 | Left = 8 64 | Top = 59 65 | Width = 66 66 | Height = 17 67 | Hint = 'Skip "read-only" memory pages' 68 | Caption = 'Skip RO' 69 | Checked = True 70 | ParentShowHint = False 71 | ShowHint = True 72 | State = cbChecked 73 | TabOrder = 2 74 | OnClick = cbSearchInputTypeChange 75 | end 76 | object ProgressBar: TProgressBar 77 | Left = 80 78 | Top = 59 79 | Width = 401 80 | Height = 17 81 | TabOrder = 3 82 | end 83 | object edStartAddr: TEdit 84 | Left = 80 85 | Top = 84 86 | Width = 137 87 | Height = 21 88 | TabOrder = 4 89 | Text = '0' 90 | OnChange = edStartAddrChange 91 | end 92 | object cbSearchInputType: TComboBox 93 | Left = 48 94 | Top = 5 95 | Width = 433 96 | Height = 21 97 | Style = csDropDownList 98 | TabOrder = 5 99 | OnChange = cbSearchInputTypeChange 100 | end 101 | object cbSearchText: TComboBox 102 | Left = 48 103 | Top = 32 104 | Width = 433 105 | Height = 21 106 | TabOrder = 6 107 | TextHint = 'Enter search pattern...' 108 | OnChange = cbSearchInputTypeChange 109 | end 110 | end 111 | -------------------------------------------------------------------------------- /src/gui/uMemoryMapListInfo.dfm: -------------------------------------------------------------------------------- 1 | object dlgMemoryMapListInfo: TdlgMemoryMapListInfo 2 | Left = 0 3 | Top = 0 4 | Caption = 'Process Memory Map - MemoryMap List Info' 5 | ClientHeight = 337 6 | ClientWidth = 635 7 | Color = clBtnFace 8 | Font.Charset = DEFAULT_CHARSET 9 | Font.Color = clWindowText 10 | Font.Height = -11 11 | Font.Name = 'Tahoma' 12 | Font.Style = [] 13 | OldCreateOrder = False 14 | Position = poMainFormCenter 15 | PixelsPerInch = 96 16 | TextHeight = 13 17 | object edReport: TRichEdit 18 | Left = 0 19 | Top = 0 20 | Width = 635 21 | Height = 337 22 | Align = alClient 23 | Font.Charset = RUSSIAN_CHARSET 24 | Font.Color = clWindowText 25 | Font.Height = -11 26 | Font.Name = 'Courier New' 27 | Font.Style = [] 28 | ParentFont = False 29 | PopupMenu = PopupMenu 30 | ReadOnly = True 31 | ScrollBars = ssBoth 32 | TabOrder = 0 33 | Zoom = 100 34 | end 35 | object PopupMenu: TPopupMenu 36 | Left = 104 37 | Top = 32 38 | object mnuCopy: TMenuItem 39 | Caption = 'Copy' 40 | ShortCut = 16451 41 | OnClick = mnuCopyClick 42 | end 43 | object SelectAll1: TMenuItem 44 | Caption = 'Select All' 45 | ShortCut = 16449 46 | OnClick = SelectAll1Click 47 | end 48 | end 49 | object SaveMMLDialog: TSaveDialog 50 | DefaultExt = 'mml' 51 | Filter = 'MemoryMap List (*.mml)|*.mml|All Files (*.*)|*.*' 52 | Options = [ofOverwritePrompt, ofHideReadOnly, ofPathMustExist, ofEnableSizing] 53 | Left = 192 54 | Top = 32 55 | end 56 | end 57 | -------------------------------------------------------------------------------- /src/gui/uMemoryMapListInfoSettings.dfm: -------------------------------------------------------------------------------- 1 | object dlgMemoryMapListInfoSettings: TdlgMemoryMapListInfoSettings 2 | Left = 0 3 | Top = 0 4 | BorderStyle = bsDialog 5 | Caption = 'Process Memory Map - MemoryMap List Info Settings' 6 | ClientHeight = 339 7 | ClientWidth = 502 8 | Color = clBtnFace 9 | Font.Charset = DEFAULT_CHARSET 10 | Font.Color = clWindowText 11 | Font.Height = -11 12 | Font.Name = 'Tahoma' 13 | Font.Style = [] 14 | OldCreateOrder = False 15 | Position = poMainFormCenter 16 | PixelsPerInch = 96 17 | TextHeight = 13 18 | object SpeedButton1: TSpeedButton 19 | Left = 471 20 | Top = 24 21 | Width = 23 22 | Height = 22 23 | Hint = 'Browse...' 24 | Caption = '...' 25 | ParentShowHint = False 26 | ShowHint = True 27 | OnClick = SpeedButton1Click 28 | end 29 | object Label1: TLabel 30 | Left = 32 31 | Top = 96 32 | Width = 52 33 | Height = 13 34 | Caption = 'Dump size:' 35 | end 36 | object SpeedButton2: TSpeedButton 37 | Left = 471 38 | Top = 232 39 | Width = 23 40 | Height = 22 41 | Hint = 'Browse...' 42 | Caption = '...' 43 | ParentShowHint = False 44 | ShowHint = True 45 | OnClick = SpeedButton2Click 46 | end 47 | object Bevel1: TBevel 48 | Left = 8 49 | Top = 152 50 | Width = 486 51 | Height = 10 52 | Shape = bsTopLine 53 | end 54 | object edMML: TLabeledEdit 55 | Left = 8 56 | Top = 24 57 | Width = 457 58 | Height = 21 59 | EditLabel.Width = 80 60 | EditLabel.Height = 13 61 | EditLabel.Caption = 'Path to MML file:' 62 | TabOrder = 0 63 | end 64 | object cbShowMiniDump: TCheckBox 65 | Left = 8 66 | Top = 72 67 | Width = 97 68 | Height = 17 69 | Caption = 'Show MiniDump' 70 | Checked = True 71 | State = cbChecked 72 | TabOrder = 1 73 | end 74 | object cbShowDisasm: TCheckBox 75 | Left = 8 76 | Top = 51 77 | Width = 97 78 | Height = 17 79 | Caption = 'Show Disasembly' 80 | TabOrder = 2 81 | end 82 | object cbDumpSize: TComboBox 83 | Left = 32 84 | Top = 115 85 | Width = 145 86 | Height = 21 87 | Style = csDropDownList 88 | ItemIndex = 4 89 | TabOrder = 3 90 | Text = '256' 91 | Items.Strings = ( 92 | '16' 93 | '32' 94 | '64' 95 | '128' 96 | '256' 97 | '512' 98 | '1024' 99 | '2048' 100 | '4096' 101 | 'Full Region Size') 102 | end 103 | object cbSave: TCheckBox 104 | Left = 8 105 | Top = 192 106 | Width = 97 107 | Height = 17 108 | Caption = 'Save Result' 109 | TabOrder = 4 110 | end 111 | object edSave: TLabeledEdit 112 | Left = 8 113 | Top = 232 114 | Width = 457 115 | Height = 21 116 | EditLabel.Width = 86 117 | EditLabel.Height = 13 118 | EditLabel.Caption = 'Path to result file:' 119 | TabOrder = 5 120 | end 121 | object cbSaveFullDump: TCheckBox 122 | Left = 32 123 | Top = 264 124 | Width = 201 125 | Height = 17 126 | Caption = 'Save Full Dump if page not Shared' 127 | Checked = True 128 | State = cbChecked 129 | TabOrder = 6 130 | end 131 | object Button1: TButton 132 | Left = 419 133 | Top = 305 134 | Width = 75 135 | Height = 25 136 | Cancel = True 137 | Caption = 'Cancel' 138 | ModalResult = 2 139 | TabOrder = 7 140 | end 141 | object Button2: TButton 142 | Left = 338 143 | Top = 305 144 | Width = 75 145 | Height = 25 146 | Caption = 'Scan' 147 | Default = True 148 | TabOrder = 8 149 | OnClick = Button2Click 150 | end 151 | object cbSaveIfWrongCRC: TCheckBox 152 | Left = 32 153 | Top = 288 154 | Width = 201 155 | Height = 17 156 | Caption = 'Save if CRC wrong' 157 | Checked = True 158 | State = cbChecked 159 | TabOrder = 9 160 | end 161 | object cbGenerateMML: TCheckBox 162 | Left = 8 163 | Top = 169 164 | Width = 194 165 | Height = 17 166 | Caption = 'Generate MML with updated CRC' 167 | TabOrder = 10 168 | end 169 | object OpenMMListDialog: TOpenDialog 170 | DefaultExt = 'mml' 171 | Filter = 'MemoryMap List (*.mml)|*.mml|All Files (*.*)|*.*' 172 | Options = [ofHideReadOnly, ofPathMustExist, ofFileMustExist, ofEnableSizing] 173 | Left = 327 174 | Top = 80 175 | end 176 | object SaveResultDialog: TSaveDialog 177 | DefaultExt = 'zip' 178 | Filter = 'ZIP archive (*.zip)|*.zip|All Files (*.*)|*.*' 179 | Options = [ofOverwritePrompt, ofHideReadOnly, ofPathMustExist, ofNoReadOnlyReturn, ofEnableSizing] 180 | Left = 440 181 | Top = 80 182 | end 183 | end 184 | -------------------------------------------------------------------------------- /src/gui/uMemoryMapListInfoSettings.pas: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // **************************************************************************** 4 | // * Project : ProcessMM 5 | // * Unit Name : uMemoryMapListInfoSettings.pas 6 | // * Purpose : Диалог настроек для процедуры сканирования памяти 7 | // * Author : Александр (Rouse_) Багель 8 | // * Copyright : © Fangorn Wizards Lab 1998 - 2016, 2023. 9 | // * Version : 1.4.30 10 | // * Home Page : http://rouse.drkb.ru 11 | // * Home Blog : http://alexander-bagel.blogspot.ru 12 | // **************************************************************************** 13 | // * Stable Release : http://rouse.drkb.ru/winapi.php#pmm2 14 | // * Latest Source : https://github.com/AlexanderBagel/ProcessMemoryMap 15 | // **************************************************************************** 16 | // 17 | 18 | unit uMemoryMapListInfoSettings; 19 | 20 | interface 21 | 22 | uses 23 | Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, 24 | Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.Buttons, Vcl.StdCtrls, Vcl.ExtCtrls, 25 | uBaseForm; 26 | 27 | type 28 | TdlgMemoryMapListInfoSettings = class(TBaseAppForm) 29 | OpenMMListDialog: TOpenDialog; 30 | edMML: TLabeledEdit; 31 | SpeedButton1: TSpeedButton; 32 | cbShowMiniDump: TCheckBox; 33 | cbShowDisasm: TCheckBox; 34 | cbDumpSize: TComboBox; 35 | Label1: TLabel; 36 | cbSave: TCheckBox; 37 | edSave: TLabeledEdit; 38 | SpeedButton2: TSpeedButton; 39 | SaveResultDialog: TSaveDialog; 40 | cbSaveFullDump: TCheckBox; 41 | Bevel1: TBevel; 42 | Button1: TButton; 43 | Button2: TButton; 44 | cbSaveIfWrongCRC: TCheckBox; 45 | cbGenerateMML: TCheckBox; 46 | procedure SpeedButton1Click(Sender: TObject); 47 | procedure SpeedButton2Click(Sender: TObject); 48 | procedure Button2Click(Sender: TObject); 49 | private 50 | { Private declarations } 51 | public 52 | { Public declarations } 53 | end; 54 | 55 | var 56 | dlgMemoryMapListInfoSettings: TdlgMemoryMapListInfoSettings; 57 | 58 | implementation 59 | 60 | {$R *.dfm} 61 | 62 | procedure TdlgMemoryMapListInfoSettings.Button2Click(Sender: TObject); 63 | begin 64 | if not FileExists(edMML.Text) then 65 | raise Exception.CreateFmt('File "%s" not found.', [edMML.Text]); 66 | if cbSave.Checked then 67 | begin 68 | if edSave.Text = '' then 69 | raise Exception.Create('Path to result file is empty.'); 70 | try 71 | TFileStream.Create(edSave.Text, fmCreate).Free; 72 | except 73 | raise Exception.CreateFmt('Can not create result file "%s".', [edSave.Text]); 74 | end; 75 | end; 76 | ModalResult := mrOk; 77 | end; 78 | 79 | procedure TdlgMemoryMapListInfoSettings.SpeedButton1Click(Sender: TObject); 80 | begin 81 | if OpenMMListDialog.Execute then 82 | edMML.Text := OpenMMListDialog.FileName; 83 | end; 84 | 85 | procedure TdlgMemoryMapListInfoSettings.SpeedButton2Click(Sender: TObject); 86 | begin 87 | if SaveResultDialog.Execute then 88 | edSave.Text := SaveResultDialog.FileName; 89 | end; 90 | 91 | end. 92 | -------------------------------------------------------------------------------- /src/gui/uPatchDetect.dfm: -------------------------------------------------------------------------------- 1 | object dlgPatches: TdlgPatches 2 | Left = 0 3 | Top = 0 4 | Caption = 'Process Memory Map - Hook Scanner' 5 | ClientHeight = 548 6 | ClientWidth = 1112 7 | Color = clBtnFace 8 | Font.Charset = DEFAULT_CHARSET 9 | Font.Color = clWindowText 10 | Font.Height = -11 11 | Font.Name = 'Tahoma' 12 | Font.Style = [] 13 | KeyPreview = True 14 | OldCreateOrder = False 15 | Position = poMainFormCenter 16 | OnClose = FormClose 17 | OnCreate = FormCreate 18 | OnDestroy = FormDestroy 19 | OnKeyPress = FormKeyPress 20 | OnShow = FormShow 21 | PixelsPerInch = 96 22 | TextHeight = 13 23 | object edLog: TRichEdit 24 | Left = 0 25 | Top = 0 26 | Width = 1112 27 | Height = 548 28 | Align = alClient 29 | Font.Charset = RUSSIAN_CHARSET 30 | Font.Color = clWindowText 31 | Font.Height = -11 32 | Font.Name = 'Courier New' 33 | Font.Style = [] 34 | ParentFont = False 35 | PopupMenu = mnuPopup 36 | ReadOnly = True 37 | ScrollBars = ssBoth 38 | TabOrder = 0 39 | Zoom = 100 40 | end 41 | object mnuPopup: TPopupMenu 42 | OnPopup = mnuPopupPopup 43 | Left = 8 44 | Top = 8 45 | object mnuGotoAddress: TMenuItem 46 | Caption = 'Go to Address...' 47 | Default = True 48 | ShortCut = 13 49 | OnClick = mnuGotoAddressClick 50 | end 51 | object N3: TMenuItem 52 | Caption = '-' 53 | end 54 | object mnuCopy: TMenuItem 55 | Caption = 'Copy' 56 | ShortCut = 16451 57 | OnClick = mnuCopyClick 58 | end 59 | object SelectAll1: TMenuItem 60 | Caption = 'Select All' 61 | ShortCut = 16449 62 | OnClick = SelectAll1Click 63 | end 64 | object N1: TMenuItem 65 | Caption = '-' 66 | end 67 | object mnuRefresh: TMenuItem 68 | Caption = 'Refresh' 69 | ShortCut = 116 70 | end 71 | end 72 | end 73 | -------------------------------------------------------------------------------- /src/gui/uProgress.dfm: -------------------------------------------------------------------------------- 1 | object dlgProgress: TdlgProgress 2 | Left = 0 3 | Top = 0 4 | BorderStyle = bsNone 5 | Caption = 'dlgProgress' 6 | ClientHeight = 67 7 | ClientWidth = 500 8 | Color = clBtnFace 9 | Font.Charset = DEFAULT_CHARSET 10 | Font.Color = clWindowText 11 | Font.Height = -11 12 | Font.Name = 'Tahoma' 13 | Font.Style = [] 14 | OldCreateOrder = False 15 | Position = poMainFormCenter 16 | OnCreate = FormCreate 17 | OnDestroy = FormDestroy 18 | PixelsPerInch = 96 19 | TextHeight = 13 20 | object Panel1: TPanel 21 | Left = 0 22 | Top = 0 23 | Width = 500 24 | Height = 67 25 | Align = alClient 26 | TabOrder = 0 27 | ExplicitWidth = 465 28 | object lblProgress: TLabel 29 | Left = 16 30 | Top = 16 31 | Width = 433 32 | Height = 13 33 | AutoSize = False 34 | Caption = 'lblProgress' 35 | EllipsisPosition = epPathEllipsis 36 | end 37 | end 38 | end 39 | -------------------------------------------------------------------------------- /src/gui/uProgress.pas: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // **************************************************************************** 4 | // * Project : ProcessMM 5 | // * Unit Name : uProgress.pas 6 | // * Purpose : Вспомогательный диалог для отображения прогреса 7 | // * Author : Александр (Rouse_) Багель 8 | // * Copyright : © Fangorn Wizards Lab 1998 - 2024. 9 | // * Version : 1.5.37 10 | // * Home Page : http://rouse.drkb.ru 11 | // * Home Blog : http://alexander-bagel.blogspot.ru 12 | // **************************************************************************** 13 | // * Stable Release : http://rouse.drkb.ru/winapi.php#pmm2 14 | // * Latest Source : https://github.com/AlexanderBagel/ProcessMemoryMap 15 | // **************************************************************************** 16 | // 17 | 18 | unit uProgress; 19 | 20 | interface 21 | 22 | uses 23 | Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, 24 | System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, 25 | Vcl.ComCtrls, Vcl.StdCtrls, Vcl.ExtCtrls, 26 | 27 | FWProgressBar, 28 | uBaseForm; 29 | 30 | type 31 | TdlgProgress = class(TBaseAppForm) 32 | Panel1: TPanel; 33 | lblProgress: TLabel; 34 | procedure FormDestroy(Sender: TObject); 35 | procedure FormCreate(Sender: TObject); 36 | private 37 | { Private declarations } 38 | public 39 | ProgressBar, ProgressBarAdv: TFWProgressBar; 40 | procedure ShowWithCallback(Value: TProc); 41 | procedure UpdateCaption(const Value: string; APosition: Integer); 42 | end; 43 | 44 | var 45 | dlgProgress: TdlgProgress; 46 | 47 | implementation 48 | 49 | uses 50 | uUtils; 51 | 52 | {$R *.dfm} 53 | 54 | { TdlgProgress } 55 | 56 | procedure TdlgProgress.FormCreate(Sender: TObject); 57 | begin 58 | ProgressBar := TFWProgressBar.Create(Self); 59 | ProgressBar.Parent := Self; 60 | ProgressBar.SetBounds( 61 | ToDpi(16, FCurrentPPI), 62 | ToDpi(35, FCurrentPPI), 63 | ClientWidth - ToDpi(16, FCurrentPPI) shl 1, 64 | ToDpi(17, FCurrentPPI)); 65 | ProgressBarAdv := TFWProgressBar.Create(Self); 66 | ProgressBarAdv.Parent := Self; 67 | ProgressBarAdv.SetBounds( 68 | ToDpi(16, FCurrentPPI), 69 | ToDpi(48, FCurrentPPI), 70 | ClientWidth - ToDpi(16, FCurrentPPI) shl 1, 71 | ToDpi(17, FCurrentPPI)); 72 | ProgressBarAdv.Visible := False; 73 | end; 74 | 75 | procedure TdlgProgress.FormDestroy(Sender: TObject); 76 | begin 77 | dlgProgress := nil; 78 | end; 79 | 80 | procedure TdlgProgress.ShowWithCallback(Value: TProc); 81 | begin 82 | Show; 83 | Application.ProcessMessages; 84 | Value; 85 | end; 86 | 87 | procedure TdlgProgress.UpdateCaption(const Value: string; APosition: Integer); 88 | begin 89 | lblProgress.Caption := Value; 90 | ProgressBar.Position := APosition; 91 | Application.ProcessMessages; 92 | end; 93 | 94 | end. 95 | -------------------------------------------------------------------------------- /src/gui/uRegionProperties.dfm: -------------------------------------------------------------------------------- 1 | object dlgRegionProps: TdlgRegionProps 2 | Left = 0 3 | Top = 0 4 | Caption = 'Process Memory Map - Region Properties' 5 | ClientHeight = 548 6 | ClientWidth = 958 7 | Color = clBtnFace 8 | Font.Charset = DEFAULT_CHARSET 9 | Font.Color = clWindowText 10 | Font.Height = -11 11 | Font.Name = 'Tahoma' 12 | Font.Style = [] 13 | KeyPreview = True 14 | OldCreateOrder = False 15 | Position = poMainFormCenter 16 | OnActivate = FormActivate 17 | OnClose = FormClose 18 | OnCreate = FormCreate 19 | OnDestroy = FormDestroy 20 | OnDeactivate = FormDeactivate 21 | OnKeyPress = FormKeyPress 22 | PixelsPerInch = 96 23 | TextHeight = 13 24 | object edProperties: TRichEdit 25 | Left = 0 26 | Top = 0 27 | Width = 958 28 | Height = 548 29 | Align = alClient 30 | Font.Charset = RUSSIAN_CHARSET 31 | Font.Color = clWindowText 32 | Font.Height = -11 33 | Font.Name = 'Courier New' 34 | Font.Style = [] 35 | HideSelection = False 36 | ParentFont = False 37 | PopupMenu = mnuPopup 38 | ReadOnly = True 39 | ScrollBars = ssBoth 40 | TabOrder = 0 41 | Zoom = 100 42 | OnMouseDown = edPropertiesMouseDown 43 | OnMouseUp = edPropertiesMouseUp 44 | end 45 | object mnuPopup: TPopupMenu 46 | OnPopup = mnuPopupPopup 47 | Left = 376 48 | Top = 248 49 | object mnuGotoAddress: TMenuItem 50 | Caption = 'Go to Address...' 51 | Default = True 52 | ShortCut = 13 53 | OnClick = mnuGotoAddressClick 54 | end 55 | object N3: TMenuItem 56 | Caption = '-' 57 | end 58 | object mnuCopy: TMenuItem 59 | Caption = 'Copy' 60 | ShortCut = 16451 61 | OnClick = mnuCopyClick 62 | end 63 | object SelectAll1: TMenuItem 64 | Caption = 'Select All' 65 | ShortCut = 16449 66 | OnClick = SelectAll1Click 67 | end 68 | object N1: TMenuItem 69 | Caption = '-' 70 | end 71 | object mnuRefresh: TMenuItem 72 | Caption = 'Refresh' 73 | ShortCut = 116 74 | OnClick = mnuRefreshClick 75 | end 76 | object N2: TMenuItem 77 | Caption = '-' 78 | end 79 | object mnuTopMostWnd: TMenuItem 80 | Caption = 'TopMost Window' 81 | ShortCut = 16468 82 | OnClick = mnuTopMostWndClick 83 | end 84 | object mnuShowAsDisassembly: TMenuItem 85 | AutoCheck = True 86 | Caption = 'Show as disassembly' 87 | ShortCut = 16452 88 | OnClick = mnuShowAsDisassemblyClick 89 | end 90 | object mnuDasmMode: TMenuItem 91 | Caption = 'Change disasm mode' 92 | object mnuDasmModeAuto: TMenuItem 93 | Caption = 'Auto detect' 94 | Checked = True 95 | GroupIndex = 1 96 | RadioItem = True 97 | OnClick = mnuDasmModeAutoClick 98 | end 99 | object mnuDasmMode86: TMenuItem 100 | Tag = 1 101 | Caption = 'x86' 102 | GroupIndex = 1 103 | RadioItem = True 104 | ShortCut = 16440 105 | OnClick = mnuDasmModeAutoClick 106 | end 107 | object mnuDasmMode64: TMenuItem 108 | Tag = 2 109 | Caption = 'x64' 110 | GroupIndex = 1 111 | RadioItem = True 112 | ShortCut = 16438 113 | OnClick = mnuDasmModeAutoClick 114 | end 115 | end 116 | end 117 | object tmrAutoRefresh: TTimer 118 | Enabled = False 119 | OnTimer = tmrAutoRefreshTimer 120 | Left = 472 121 | Top = 280 122 | end 123 | end 124 | -------------------------------------------------------------------------------- /src/gui/uSearchResult.dfm: -------------------------------------------------------------------------------- 1 | object dlgSearchResult: TdlgSearchResult 2 | Left = 0 3 | Top = 0 4 | Caption = 'Process Memory Map - Search Results' 5 | ClientHeight = 411 6 | ClientWidth = 852 7 | Color = clBtnFace 8 | Font.Charset = DEFAULT_CHARSET 9 | Font.Color = clWindowText 10 | Font.Height = -11 11 | Font.Name = 'Tahoma' 12 | Font.Style = [] 13 | KeyPreview = True 14 | OldCreateOrder = False 15 | Position = poScreenCenter 16 | OnClose = FormClose 17 | OnKeyPress = FormKeyPress 18 | PixelsPerInch = 96 19 | TextHeight = 13 20 | object PageControl: TPageControl 21 | Left = 0 22 | Top = 0 23 | Width = 852 24 | Height = 411 25 | Align = alClient 26 | PopupMenu = pmPage 27 | TabOrder = 0 28 | end 29 | object pmViewer: TPopupMenu 30 | Left = 248 31 | Top = 176 32 | object mnuOpen: TMenuItem 33 | Action = acOpen 34 | Default = True 35 | end 36 | object CopyAddress1: TMenuItem 37 | Action = acCopyAddr 38 | end 39 | object N1: TMenuItem 40 | Caption = '-' 41 | end 42 | object Close1: TMenuItem 43 | Action = acClose 44 | end 45 | object CloseAllButThis1: TMenuItem 46 | Caption = 'Close Multiple Pages' 47 | object CloseAllButThis2: TMenuItem 48 | Action = acCloseAllButThis 49 | end 50 | object CloseAlltotheLeft1: TMenuItem 51 | Action = acCloseLeft 52 | end 53 | object CloseAlltotheRight1: TMenuItem 54 | Action = acCloseRight 55 | end 56 | object N3: TMenuItem 57 | Caption = '-' 58 | end 59 | object CloseAll1: TMenuItem 60 | Action = acCloseAll 61 | end 62 | end 63 | end 64 | object ActionList1: TActionList 65 | Left = 472 66 | Top = 208 67 | object acOpen: TAction 68 | Caption = 'Open' 69 | OnExecute = acOpenExecute 70 | OnUpdate = acOpenUpdate 71 | end 72 | object acCopyAddr: TAction 73 | Caption = 'Copy Address' 74 | OnExecute = acCopyAddrExecute 75 | OnUpdate = acOpenUpdate 76 | end 77 | object acClose: TAction 78 | Caption = 'Close Page' 79 | OnExecute = acCloseExecute 80 | end 81 | object acCloseAll: TAction 82 | Caption = 'Close All' 83 | OnExecute = acCloseAllExecute 84 | end 85 | object acCloseLeft: TAction 86 | Caption = 'Close All to the Left' 87 | OnExecute = acCloseLeftExecute 88 | OnUpdate = acCloseLeftUpdate 89 | end 90 | object acCloseRight: TAction 91 | Caption = 'Close All to the Right' 92 | OnExecute = acCloseRightExecute 93 | OnUpdate = acCloseRightUpdate 94 | end 95 | object acCloseAllButThis: TAction 96 | Caption = 'Close All But This' 97 | OnExecute = acCloseAllButThisExecute 98 | OnUpdate = acCloseAllButThisUpdate 99 | end 100 | end 101 | object pmPage: TPopupMenu 102 | Left = 328 103 | Top = 176 104 | object MenuItem4: TMenuItem 105 | Action = acClose 106 | end 107 | object MenuItem5: TMenuItem 108 | Caption = '-' 109 | end 110 | object MenuItem6: TMenuItem 111 | Action = acCloseAllButThis 112 | end 113 | object MenuItem7: TMenuItem 114 | Action = acCloseLeft 115 | end 116 | object MenuItem8: TMenuItem 117 | Action = acCloseRight 118 | end 119 | object N2: TMenuItem 120 | Caption = '-' 121 | end 122 | object MenuItem9: TMenuItem 123 | Action = acCloseAll 124 | end 125 | end 126 | end 127 | -------------------------------------------------------------------------------- /src/gui/uSelectAddress.dfm: -------------------------------------------------------------------------------- 1 | object dlgSelectAddress: TdlgSelectAddress 2 | Left = 0 3 | Top = 0 4 | BorderStyle = bsDialog 5 | Caption = 'Process Memory Map - Query Address' 6 | ClientHeight = 130 7 | ClientWidth = 321 8 | Color = clBtnFace 9 | Font.Charset = DEFAULT_CHARSET 10 | Font.Color = clWindowText 11 | Font.Height = -11 12 | Font.Name = 'Tahoma' 13 | Font.Style = [] 14 | OldCreateOrder = False 15 | Position = poMainFormCenter 16 | PixelsPerInch = 96 17 | TextHeight = 13 18 | object Label1: TLabel 19 | Left = 16 20 | Top = 16 21 | Width = 115 22 | Height = 13 23 | Caption = 'Enter address to query:' 24 | end 25 | object Label2: TLabel 26 | Left = 32 27 | Top = 40 28 | Width = 17 29 | Height = 13 30 | Caption = 'INT' 31 | end 32 | object lblHex: TLabel 33 | Left = 26 34 | Top = 67 35 | Width = 19 36 | Height = 13 37 | Caption = 'HEX' 38 | end 39 | object lblSizeInt: TLabel 40 | Left = 32 41 | Top = 108 42 | Width = 17 43 | Height = 13 44 | Caption = 'INT' 45 | Visible = False 46 | end 47 | object lblSize: TLabel 48 | Left = 16 49 | Top = 88 50 | Width = 51 51 | Height = 13 52 | Caption = 'Enter size:' 53 | Visible = False 54 | end 55 | object edInt: TEdit 56 | Left = 54 57 | Top = 37 58 | Width = 253 59 | Height = 21 60 | TabOrder = 1 61 | Text = '0' 62 | OnChange = edIntChange 63 | OnKeyPress = edIntKeyPress 64 | end 65 | object edHex: TEdit 66 | Left = 54 67 | Top = 64 68 | Width = 253 69 | Height = 21 70 | TabOrder = 0 71 | Text = '0' 72 | OnChange = edHexChange 73 | end 74 | object btnCancel: TButton 75 | Left = 232 76 | Top = 99 77 | Width = 75 78 | Height = 25 79 | Cancel = True 80 | Caption = 'Cancel' 81 | ModalResult = 2 82 | TabOrder = 2 83 | end 84 | object btnOk: TButton 85 | Left = 151 86 | Top = 99 87 | Width = 75 88 | Height = 25 89 | Caption = 'OK' 90 | Default = True 91 | ModalResult = 1 92 | TabOrder = 3 93 | end 94 | object edSize: TEdit 95 | Left = 54 96 | Top = 105 97 | Width = 253 98 | Height = 21 99 | TabOrder = 4 100 | Text = '0' 101 | Visible = False 102 | OnChange = edIntChange 103 | OnKeyPress = edIntKeyPress 104 | end 105 | end 106 | -------------------------------------------------------------------------------- /src/gui/uSelectAddress.pas: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // **************************************************************************** 4 | // * Project : ProcessMM 5 | // * Unit Name : uSelectAddress.pas 6 | // * Purpose : Диалог для выбора адреса 7 | // * Author : Александр (Rouse_) Багель 8 | // * Copyright : © Fangorn Wizards Lab 1998 - 2016, 2023. 9 | // * Version : 1.4.30 10 | // * Home Page : http://rouse.drkb.ru 11 | // * Home Blog : http://alexander-bagel.blogspot.ru 12 | // **************************************************************************** 13 | // * Stable Release : http://rouse.drkb.ru/winapi.php#pmm2 14 | // * Latest Source : https://github.com/AlexanderBagel/ProcessMemoryMap 15 | // **************************************************************************** 16 | // 17 | 18 | unit uSelectAddress; 19 | 20 | interface 21 | 22 | uses 23 | Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, 24 | System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, 25 | Vcl.StdCtrls, uBaseForm; 26 | 27 | type 28 | TCaptionType = (ctDump, ctHighLight, ctQuery); 29 | TdlgSelectAddress = class(TBaseAppForm) 30 | Label1: TLabel; 31 | Label2: TLabel; 32 | edInt: TEdit; 33 | lblHex: TLabel; 34 | edHex: TEdit; 35 | btnCancel: TButton; 36 | btnOk: TButton; 37 | edSize: TEdit; 38 | lblSizeInt: TLabel; 39 | lblSize: TLabel; 40 | procedure edIntKeyPress(Sender: TObject; var Key: Char); 41 | procedure edIntChange(Sender: TObject); 42 | procedure edHexChange(Sender: TObject); 43 | private 44 | InChange: Boolean; 45 | public 46 | function ShowDlg(CaptionType: TCaptionType; ASelectAddress: UInt64 = 0): TModalResult; 47 | end; 48 | 49 | var 50 | dlgSelectAddress: TdlgSelectAddress; 51 | 52 | implementation 53 | 54 | uses 55 | uUtils; 56 | 57 | {$R *.dfm} 58 | 59 | function TrimZeros(const Value: string): string; 60 | var 61 | I: Integer; 62 | begin 63 | Result := ''; 64 | for I := 1 to Length(Value) do 65 | if Value[I] <> '0' then 66 | begin 67 | Result := Copy(Value, I, Length(Value)); 68 | Break; 69 | end; 70 | if Result = '' then 71 | Result := '0'; 72 | end; 73 | 74 | procedure TdlgSelectAddress.edHexChange(Sender: TObject); 75 | var 76 | TmpValue: string; 77 | Index: Integer; 78 | Valid: Boolean; 79 | CalculatedAddr, LeftVal, RightVal: Int64; 80 | begin 81 | if InChange then Exit; 82 | InChange := True; 83 | try 84 | TmpValue := edHex.Text; 85 | if TmpValue = '' then 86 | begin 87 | edHex.Text := '0'; 88 | btnOk.Enabled := True; 89 | Exit; 90 | end; 91 | 92 | CalculatedAddr := 0; 93 | TmpValue := StringReplace(TmpValue, ' ', '', [rfReplaceAll]); 94 | 95 | Valid := HexValueToInt64(TmpValue, LeftVal); 96 | if Valid then 97 | CalculatedAddr := LeftVal 98 | else 99 | begin 100 | 101 | // минимальный набор адресной арифметики для быстрого перехода по оффсету 102 | 103 | Index := Pos('+', TmpValue); 104 | if Index > 0 then 105 | begin 106 | Valid := 107 | HexValueToInt64(Copy(TmpValue, 1, Index - 1), LeftVal) and 108 | HexValueToInt64(Copy(TmpValue, Index + 1, Length(TmpValue)), RightVal); 109 | CalculatedAddr := LeftVal + RightVal; 110 | end 111 | else 112 | begin 113 | Index := Pos('-', TmpValue); 114 | if Index > 0 then 115 | begin 116 | Valid := 117 | HexValueToInt64(Copy(TmpValue, 1, Index - 1), LeftVal) and 118 | HexValueToInt64(Copy(TmpValue, Index + 1, Length(TmpValue)), RightVal); 119 | CalculatedAddr := LeftVal - RightVal; 120 | end; 121 | end; 122 | end; 123 | 124 | if Valid then 125 | lblHex.Font.Color := clWindowText 126 | else 127 | lblHex.Font.Color := clRed; 128 | 129 | edInt.Text := IntToStr(CalculatedAddr); 130 | 131 | finally 132 | InChange := False; 133 | end; 134 | end; 135 | 136 | procedure TdlgSelectAddress.edIntChange(Sender: TObject); 137 | var 138 | I: Int64; 139 | Edit: TEdit; 140 | begin 141 | if InChange then Exit; 142 | InChange := True; 143 | try 144 | Edit := Sender as TEdit; 145 | if Edit.Text = '' then 146 | Edit.Text := '0'; 147 | if not TryStrToInt64(Edit.Text, I) then 148 | begin 149 | ShowErrorHint(Edit.Handle); 150 | Edit.Text := '0'; 151 | end; 152 | if Edit = edInt then 153 | begin 154 | edHex.Text := TrimZeros(IntToHex(StrToInt64Def(Edit.Text, 0), 16)); 155 | lblHex.Font.Color := clWindowText; 156 | end; 157 | finally 158 | InChange := False; 159 | end; 160 | end; 161 | 162 | procedure TdlgSelectAddress.edIntKeyPress(Sender: TObject; var Key: Char); 163 | begin 164 | if not CharInSet(Key, [#8, #22, '0'..'9']) then 165 | begin 166 | Key := #0; 167 | ShowErrorHint((Sender as TEdit).Handle); 168 | end; 169 | end; 170 | 171 | function TdlgSelectAddress.ShowDlg(CaptionType: TCaptionType; 172 | ASelectAddress: UInt64): TModalResult; 173 | var 174 | Offset: Integer; 175 | begin 176 | if ASelectAddress <> 0 then 177 | begin 178 | InChange := True; 179 | try 180 | edHex.Text := TrimZeros(IntToHex(ASelectAddress, 16)); 181 | edInt.Text := IntToStr(ASelectAddress); 182 | finally 183 | InChange := False; 184 | end; 185 | end; 186 | if CaptionType = ctHighLight then 187 | Caption := 'Process Memory Map - HighLight Address'; 188 | if CaptionType = ctDump then 189 | begin 190 | Caption := 'Process Memory Map - Dump Address'; 191 | lblSize.Visible := True; 192 | lblSizeInt.Visible := True; 193 | edSize.Visible := True; 194 | Offset := edSize.Top - edHex.Top; 195 | btnOk.Top := btnOk.Top + Offset; 196 | btnCancel.Top := btnCancel.Top + Offset; 197 | Height := Height + Offset; 198 | end; 199 | Result := ShowModal; 200 | end; 201 | 202 | end. 203 | -------------------------------------------------------------------------------- /src/gui/uSelectProcess.dfm: -------------------------------------------------------------------------------- 1 | object dlgSelectProcess: TdlgSelectProcess 2 | Left = 0 3 | Top = 0 4 | Caption = 'Process Memory Map - Select Process' 5 | ClientHeight = 350 6 | ClientWidth = 546 7 | Color = clBtnFace 8 | Font.Charset = DEFAULT_CHARSET 9 | Font.Color = clWindowText 10 | Font.Height = -11 11 | Font.Name = 'Tahoma' 12 | Font.Style = [] 13 | OldCreateOrder = False 14 | Position = poScreenCenter 15 | OnCreate = FormCreate 16 | OnDestroy = FormDestroy 17 | DesignSize = ( 18 | 546 19 | 350) 20 | PixelsPerInch = 96 21 | TextHeight = 13 22 | object lvProcess: TListView 23 | Left = 0 24 | Top = 0 25 | Width = 546 26 | Height = 311 27 | Align = alTop 28 | Anchors = [akLeft, akTop, akRight, akBottom] 29 | Columns = < 30 | item 31 | Caption = 'Name' 32 | Width = 150 33 | end 34 | item 35 | Alignment = taRightJustify 36 | Caption = 'PID' 37 | Width = 75 38 | end 39 | item 40 | AutoSize = True 41 | Caption = 'User' 42 | end> 43 | Groups = < 44 | item 45 | Header = 'Newest Processes' 46 | GroupID = 0 47 | State = [lgsNormal] 48 | HeaderAlign = taLeftJustify 49 | FooterAlign = taLeftJustify 50 | TitleImage = -1 51 | end 52 | item 53 | Header = 'Other processes' 54 | GroupID = 1 55 | State = [lgsNormal] 56 | HeaderAlign = taLeftJustify 57 | FooterAlign = taLeftJustify 58 | TitleImage = -1 59 | end> 60 | ReadOnly = True 61 | RowSelect = True 62 | SmallImages = il16 63 | TabOrder = 0 64 | ViewStyle = vsReport 65 | OnColumnClick = lvProcessColumnClick 66 | OnDblClick = lvProcessDblClick 67 | OnMouseUp = lvProcessMouseUp 68 | OnSelectItem = lvProcessSelectItem 69 | end 70 | object btnRefresh: TButton 71 | Left = 8 72 | Top = 317 73 | Width = 75 74 | Height = 25 75 | Anchors = [akLeft, akBottom] 76 | Caption = 'Refresh' 77 | TabOrder = 1 78 | OnClick = btnRefreshClick 79 | end 80 | object btnShowAll: TButton 81 | Left = 170 82 | Top = 317 83 | Width = 129 84 | Height = 25 85 | Anchors = [akLeft, akBottom] 86 | Caption = 'Show all processes' 87 | ElevationRequired = True 88 | TabOrder = 2 89 | OnClick = btnShowAllClick 90 | end 91 | object btnCancel: TButton 92 | Left = 463 93 | Top = 317 94 | Width = 75 95 | Height = 25 96 | Anchors = [akRight, akBottom] 97 | Cancel = True 98 | Caption = 'Cancel' 99 | ModalResult = 2 100 | TabOrder = 3 101 | end 102 | object btnDefault: TButton 103 | Left = 382 104 | Top = 317 105 | Width = 75 106 | Height = 25 107 | Anchors = [akRight, akBottom] 108 | Caption = 'OK' 109 | Default = True 110 | TabOrder = 4 111 | OnClick = btnDefaultClick 112 | end 113 | object btnNew: TButton 114 | Left = 89 115 | Top = 317 116 | Width = 75 117 | Height = 25 118 | Anchors = [akLeft, akBottom] 119 | Caption = 'New...' 120 | TabOrder = 5 121 | OnClick = btnNewClick 122 | end 123 | object il16: TImageList 124 | ColorDepth = cd32Bit 125 | Left = 16 126 | Top = 32 127 | end 128 | object odNewProcess: TOpenDialog 129 | Filter = 'Excutable file (*.exe)|*.exe|All files (*.*)|*.*' 130 | Left = 72 131 | Top = 32 132 | end 133 | end 134 | -------------------------------------------------------------------------------- /src/gui/uStringsViewer.dfm: -------------------------------------------------------------------------------- 1 | object dlgStringsViewer: TdlgStringsViewer 2 | Left = 0 3 | Top = 0 4 | ActiveControl = lvStrings 5 | Caption = 'Process Memory Map - Strings' 6 | ClientHeight = 411 7 | ClientWidth = 852 8 | Color = clBtnFace 9 | Font.Charset = DEFAULT_CHARSET 10 | Font.Color = clWindowText 11 | Font.Height = -11 12 | Font.Name = 'Tahoma' 13 | Font.Style = [] 14 | KeyPreview = True 15 | OldCreateOrder = False 16 | Position = poMainFormCenter 17 | OnClose = FormClose 18 | OnCreate = FormCreate 19 | OnDestroy = FormDestroy 20 | OnKeyPress = FormKeyPress 21 | OnShow = FormShow 22 | PixelsPerInch = 96 23 | TextHeight = 13 24 | object lvStrings: TVirtualStringTree 25 | Left = 0 26 | Top = 0 27 | Width = 852 28 | Height = 411 29 | AccessibleName = 'Data' 30 | Align = alClient 31 | Header.AutoSizeIndex = -1 32 | Header.Height = 24 33 | Header.Options = [hoAutoResize, hoColumnResize, hoDrag, hoShowSortGlyphs, hoVisible] 34 | PopupMenu = pmCopy 35 | TabOrder = 0 36 | TreeOptions.MiscOptions = [toAcceptOLEDrop, toFullRepaintOnResize, toInitOnSave, toWheelPanning, toEditOnClick] 37 | TreeOptions.PaintOptions = [toHideFocusRect, toShowButtons, toShowDropmark, toShowRoot, toShowVertGridLines, toThemeAware, toUseBlendedImages, toUseBlendedSelection, toUseExplorerTheme] 38 | TreeOptions.SelectionOptions = [toFullRowSelect] 39 | OnDblClick = lvStringsDblClick 40 | OnGetText = lvStringsGetText 41 | OnHeaderClick = lvStringsHeaderClick 42 | Touch.InteractiveGestures = [igPan, igPressAndTap] 43 | Touch.InteractiveGestureOptions = [igoPanSingleFingerHorizontal, igoPanSingleFingerVertical, igoPanInertia, igoPanGutter, igoParentPassthrough] 44 | Columns = < 45 | item 46 | Position = 0 47 | Text = 'Address' 48 | Width = 125 49 | end 50 | item 51 | Position = 1 52 | Text = 'Module' 53 | Width = 200 54 | end 55 | item 56 | Position = 2 57 | Text = 'Type' 58 | Width = 75 59 | end 60 | item 61 | Position = 3 62 | Text = 'Data' 63 | Width = 452 64 | end> 65 | end 66 | object pmCopy: TPopupMenu 67 | Left = 32 68 | Top = 32 69 | object mnuGotoAddress: TMenuItem 70 | Caption = 'Go to Address' 71 | Default = True 72 | ShortCut = 13 73 | OnClick = mnuGotoAddressClick 74 | end 75 | object mnuSeparator1: TMenuItem 76 | Caption = '-' 77 | end 78 | object mnuCopyAddress: TMenuItem 79 | Caption = 'Copy Address' 80 | OnClick = mnuCopyAddressClick 81 | end 82 | object mnuCopyFunctionName: TMenuItem 83 | Caption = 'Copy String' 84 | OnClick = mnuCopyFunctionNameClick 85 | end 86 | object mnuCopyLine: TMenuItem 87 | Caption = 'Copy Line' 88 | OnClick = mnuCopyLineClick 89 | end 90 | object mnuSeparator2: TMenuItem 91 | Caption = '-' 92 | end 93 | object mnuNextMatch: TMenuItem 94 | Caption = 'Next Match' 95 | ShortCut = 114 96 | OnClick = mnuNextMatchClick 97 | end 98 | end 99 | end 100 | -------------------------------------------------------------------------------- /src/uDump.pas: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // **************************************************************************** 4 | // * Project : ProcessMM 5 | // * Unit Name : uDump.pas 6 | // * Purpose : Вспомогательный модуль для дампа памяти процесса 7 | // * Author : Александр (Rouse_) Багель 8 | // * Copyright : © Fangorn Wizards Lab 1998 - 2013. 9 | // * Version : 1.0 10 | // * Home Page : http://rouse.drkb.ru 11 | // * Home Blog : http://alexander-bagel.blogspot.ru 12 | // **************************************************************************** 13 | // * Stable Release : http://rouse.drkb.ru/winapi.php#pmm2 14 | // * Latest Source : https://github.com/AlexanderBagel/ProcessMemoryMap 15 | // **************************************************************************** 16 | // 17 | 18 | unit uDump; 19 | 20 | interface 21 | 22 | uses 23 | Winapi.Windows, 24 | System.SysUtils, 25 | System.Classes, 26 | MemoryMap.Core, 27 | MemoryMap.Utils, 28 | MemoryMap.RegionData; 29 | 30 | function DumpAddr(const FileName: string; 31 | Address: Pointer; Size: NativeUInt = 0): NativeInt; 32 | function DumpRegion(const FileName: string; Value: TRegionData): NativeInt; 33 | 34 | implementation 35 | 36 | uses 37 | uUtils, 38 | uSettings; 39 | 40 | function DumpAddr(const FileName: string; 41 | Address: Pointer; Size: NativeUInt): NativeInt; 42 | var 43 | Process: THandle; 44 | ProcessLock: TProcessLockHandleList; 45 | Dummy: NativeUInt; 46 | Buff: array of Byte; 47 | MBI: TMemoryBasicInformation; 48 | dwLength: Cardinal; 49 | F: TFileStream; 50 | begin 51 | ProcessLock := nil; 52 | Process := OpenProcessWithReconnect; 53 | try 54 | if Settings.SuspendProcess then 55 | ProcessLock := SuspendProcess(MemoryMapCore.PID); 56 | try 57 | if Size = 0 then 58 | begin 59 | dwLength := SizeOf(TMemoryBasicInformation); 60 | if VirtualQueryEx(Process, 61 | Address, MBI, dwLength) <> dwLength then 62 | RaiseLastOSError; 63 | Size := MBI.RegionSize; 64 | end; 65 | SetLength(Buff, Size); 66 | if ReadProcessData(Process, Address, @Buff[0], Size, 67 | Dummy, rcReadAllwais) then 68 | begin 69 | F := TFileStream.Create(FileName, fmCreate); 70 | try 71 | F.WriteBuffer(Buff[0], Size); 72 | finally 73 | F.Free; 74 | end; 75 | end; 76 | Result := Size; 77 | finally 78 | if Settings.SuspendProcess then 79 | ResumeProcess(ProcessLock); 80 | end; 81 | finally 82 | CloseHandle(Process); 83 | end; 84 | end; 85 | 86 | function DumpRegion(const FileName: string; Value: TRegionData): NativeInt; 87 | begin 88 | Result := DumpAddr(FileName, Value.MBI.BaseAddress, Value.MBI.RegionSize); 89 | end; 90 | 91 | end. 92 | -------------------------------------------------------------------------------- /src/uIPC.pas: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // **************************************************************************** 4 | // * Project : ProcessMM 5 | // * Unit Name : uIPC.pas 6 | // * Purpose : Модуль для обмена данными о кучах между процессами 7 | // * Author : Александр (Rouse_) Багель 8 | // * Copyright : © Fangorn Wizards Lab 1998 - 2013, 2022. 9 | // * Version : 1.3.19 10 | // * Home Page : http://rouse.drkb.ru 11 | // * Home Blog : http://alexander-bagel.blogspot.ru 12 | // **************************************************************************** 13 | // * Stable Release : http://rouse.drkb.ru/winapi.php#pmm2 14 | // * Latest Source : https://github.com/AlexanderBagel/ProcessMemoryMap 15 | // **************************************************************************** 16 | // 17 | 18 | unit uIPC; 19 | 20 | interface 21 | 22 | uses 23 | Windows, 24 | Messages, 25 | Classes, 26 | SysUtils, 27 | MemoryMap.Heaps; 28 | 29 | const 30 | WM_GETMEMORYMAP = WM_USER + 123; 31 | 32 | type 33 | PRemoteData = ^TRemoteData; 34 | TRemoteData = packed record 35 | Address, Size: DWORD; 36 | end; 37 | 38 | PIPCServerParams = ^TIPCServerParams; 39 | TIPCServerParams = packed record 40 | PID: DWORD; 41 | WndHandle: THandle; 42 | end; 43 | 44 | TIPCServer = class 45 | private 46 | FMMFHandle: THandle; 47 | FIPCServerParams: TIPCServerParams; 48 | FMMFName: string; 49 | FMemoryMapData: array of Byte; 50 | FRemoteData: TRemoteData; 51 | protected 52 | procedure InitFileMapping; 53 | procedure ReleaseFileMapping; 54 | procedure WndProc(var Message: TMessage); 55 | public 56 | constructor Create; 57 | destructor Destroy; override; 58 | property MMFName: string read FMMFName; 59 | property WndHandle: THandle read FIPCServerParams.WndHandle; 60 | end; 61 | 62 | function GetWin32MemoryMap(PID: DWORD; const MMFName: string): TMemoryStream; 63 | procedure LoadHeaps(Value: THeap; AStream: TStream); 64 | 65 | implementation 66 | 67 | procedure SaveHeaps(Value: THeap; AStream: TStream); 68 | var 69 | HD: THeapData; 70 | begin 71 | for HD in Value.Data do 72 | begin 73 | AStream.WriteBuffer(HD.ID, 4); 74 | AStream.WriteBuffer(HD.Entry.Address, 4); 75 | AStream.WriteBuffer(HD.Entry.Size, 4); 76 | AStream.WriteBuffer(HD.Entry.Flags, 4); 77 | end; 78 | end; 79 | 80 | procedure LoadHeaps(Value: THeap; AStream: TStream); 81 | var 82 | HD: THeapData; 83 | begin 84 | ZeroMemory(@HD, SizeOf(THeapData)); 85 | while AStream.Position < AStream.Size do 86 | begin 87 | AStream.ReadBuffer(HD.ID, 4); 88 | AStream.ReadBuffer(HD.Entry.Address, 4); 89 | AStream.ReadBuffer(HD.Entry.Size, 4); 90 | AStream.ReadBuffer(HD.Entry.Flags, 4); 91 | HD.Wow64 := True; 92 | Value.Data.Add(HD); 93 | end; 94 | end; 95 | 96 | { TIPCServer } 97 | 98 | constructor TIPCServer.Create; 99 | begin 100 | Randomize; 101 | // Директива SINGLE_INSTANCE не дает запускать 32 битному приложению 64 битный аналог 102 | // Сугубо для отладки 103 | FMMFName := 'Process_Memory_Map_MMF'; 104 | {$IFNDEF SINGLE_INSTANCE} 105 | FMMFName := FMMFName + IntToHex(Random(MaxInt), 1); 106 | {$ENDIF} 107 | InitFileMapping; 108 | end; 109 | 110 | destructor TIPCServer.Destroy; 111 | begin 112 | ReleaseFileMapping; 113 | inherited; 114 | end; 115 | 116 | procedure TIPCServer.InitFileMapping; 117 | var 118 | MMFData: Pointer; 119 | begin 120 | FIPCServerParams.PID := GetCurrentProcessId; 121 | FIPCServerParams.WndHandle := Classes.AllocateHWnd(WndProc); 122 | FMMFHandle := CreateFileMapping($FFFFFFFF, nil, PAGE_READWRITE, 123 | 0, 4096, PChar(MMFName)); 124 | if FMMFHandle <> 0 then 125 | begin 126 | MMFData := MapViewOfFile(FMMFHandle, FILE_MAP_WRITE, 0, 0, 0); 127 | if MMFData <> nil then 128 | begin 129 | PIPCServerParams(MMFData)^ := FIPCServerParams; 130 | UnmapViewOfFile(MMFData); 131 | end; 132 | end; 133 | end; 134 | 135 | procedure TIPCServer.ReleaseFileMapping; 136 | begin 137 | Classes.DeallocateHWnd(FIPCServerParams.WndHandle); 138 | CloseHandle(FMMFHandle); 139 | end; 140 | 141 | procedure TIPCServer.WndProc(var Message: TMessage); 142 | var 143 | Process: THandle; 144 | H: THeap; 145 | M: TMemoryStream; 146 | begin 147 | if (Message.Msg = WM_GETMEMORYMAP) and 148 | (Message.WParam = 0) then 149 | begin 150 | Process := OpenProcess(PROCESS_QUERY_INFORMATION or PROCESS_VM_READ, 151 | False, Message.LParam); 152 | if Process = 0 then Exit; 153 | try 154 | M := TMemoryStream.Create; 155 | try 156 | H := THeap.Create(Message.LParam, Process); 157 | try 158 | SaveHeaps(H, M); 159 | finally 160 | H.Free; 161 | end; 162 | M.Position := 0; 163 | SetLength(FMemoryMapData, M.Size); 164 | M.ReadBuffer(FMemoryMapData[0], M.Size); 165 | FRemoteData.Address := DWORD(@FMemoryMapData[0]); 166 | FRemoteData.Size := M.Size; 167 | Message.Result := LRESULT(@FRemoteData); 168 | Exit; 169 | finally 170 | M.Free; 171 | end; 172 | finally 173 | CloseHandle(Process); 174 | end; 175 | end; 176 | inherited; 177 | end; 178 | 179 | function GetWin32MemoryMap(PID: DWORD; const MMFName: string): TMemoryStream; 180 | var 181 | RemoteDataAddr: DWORD; 182 | RemoteData: TRemoteData; 183 | MemoryMapData: array of Byte; 184 | MMFHandle: THandle; 185 | Data: Pointer; 186 | IPCServerParams: TIPCServerParams; 187 | Process: THandle; 188 | lpNumberOfBytesRead: SIZE_T; 189 | begin 190 | Result := TMemoryStream.Create; 191 | IPCServerParams.WndHandle := 0; 192 | MMFHandle := OpenFileMapping(FILE_MAP_READ, False, PChar(MMFName)); 193 | if MMFHandle = 0 then Exit; 194 | try 195 | Data := MapViewOfFile(MMFHandle, FILE_MAP_READ, 0, 0, 0); 196 | if Data = nil then Exit; 197 | try 198 | IPCServerParams := PIPCServerParams(Data)^; 199 | except 200 | // Другое приложение файл создало, но еще ничего туда не записало.. 201 | on EAccessViolation do ; 202 | end; 203 | finally 204 | CloseHandle(MMFHandle); 205 | end; 206 | if IPCServerParams.WndHandle = 0 then Exit; 207 | RemoteDataAddr := DWORD(SendMessage(IPCServerParams.WndHandle, 208 | WM_GETMEMORYMAP, 0, PID)); 209 | Process := OpenProcess(PROCESS_QUERY_INFORMATION or PROCESS_VM_READ, 210 | False, IPCServerParams.PID); 211 | if Process = 0 then Exit; 212 | try 213 | if not ReadProcessMemory(Process, Pointer(RemoteDataAddr), @RemoteData, 214 | SizeOf(TRemoteData), lpNumberOfBytesRead) then Exit; 215 | SetLength(MemoryMapData, RemoteData.Size); 216 | if not ReadProcessMemory(Process, Pointer(RemoteData.Address), 217 | @MemoryMapData[0], RemoteData.Size, lpNumberOfBytesRead) then Exit; 218 | Result.WriteBuffer(MemoryMapData[0], RemoteData.Size); 219 | Result.Position := 0; 220 | finally 221 | CloseHandle(Process); 222 | end; 223 | end; 224 | 225 | end. 226 | -------------------------------------------------------------------------------- /src/uProcessReconnect.pas: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // **************************************************************************** 4 | // * Project : ProcessMM 5 | // * Unit Name : uProcessReconnect.pas 6 | // * Purpose : Модуль отвечающий за поиск нового PID процесса после его перезапуска 7 | // * Author : Александр (Rouse_) Багель 8 | // * Copyright : © Fangorn Wizards Lab 1998 - 2017, 2023. 9 | // * Version : 1.4.28 10 | // * Home Page : http://rouse.drkb.ru 11 | // * Home Blog : http://alexander-bagel.blogspot.ru 12 | // **************************************************************************** 13 | // * Stable Release : http://rouse.drkb.ru/winapi.php#pmm2 14 | // * Latest Source : https://github.com/AlexanderBagel/ProcessMemoryMap 15 | // **************************************************************************** 16 | // 17 | 18 | unit uProcessReconnect; 19 | 20 | interface 21 | 22 | uses 23 | Winapi.Windows, 24 | System.Classes, 25 | Winapi.TlHelp32; 26 | 27 | type 28 | TProcessReconnect = class 29 | private 30 | FProcessData: TStringList; 31 | public 32 | constructor Create; 33 | destructor Destroy; override; 34 | procedure Clear; 35 | function GetNewPID(OldPID: DWORD): DWORD; 36 | procedure SetKnownProcessList(Value: TStringList); 37 | end; 38 | 39 | function ProcessReconnect: TProcessReconnect; 40 | 41 | implementation 42 | 43 | uses 44 | MemoryMap.Core, 45 | uUtils; 46 | 47 | var 48 | _ProcessReconnect: TProcessReconnect; 49 | 50 | function ProcessReconnect: TProcessReconnect; 51 | begin 52 | if _ProcessReconnect = nil then 53 | _ProcessReconnect := TProcessReconnect.Create; 54 | Result := _ProcessReconnect; 55 | end; 56 | 57 | { TProcessReconnect } 58 | 59 | procedure TProcessReconnect.Clear; 60 | begin 61 | FProcessData.Clear; 62 | end; 63 | 64 | constructor TProcessReconnect.Create; 65 | begin 66 | FProcessData := TStringList.Create; 67 | end; 68 | 69 | destructor TProcessReconnect.Destroy; 70 | begin 71 | FProcessData.Free; 72 | inherited; 73 | end; 74 | 75 | function TProcessReconnect.GetNewPID(OldPID: DWORD): DWORD; 76 | var 77 | Index: Integer; 78 | ProcessName: string; 79 | hProcessSnap: THandle; 80 | ProcessEntry: TProcessEntry32; 81 | Process: THandle; 82 | MBI: TMemoryBasicInformation; 83 | begin 84 | Result := 0; 85 | Process := OpenProcess(PROCESS_QUERY_INFORMATION or PROCESS_VM_READ or 86 | PROCESS_VM_OPERATION, False, OldPID); 87 | if Process <> 0 then 88 | try 89 | // дополнительная проверка, если кто-то держит хэндл на уже убитый процесс 90 | if VirtualQueryEx(Process, MemoryMapCore.PebBaseAddress, MBI, SizeOf(MBI)) <> 0 then 91 | Exit(OldPID); 92 | finally 93 | CloseHandle(Process); 94 | end; 95 | Index := FProcessData.IndexOfObject(Pointer(OldPID)); 96 | if Index < 0 then Exit; 97 | ProcessName := FProcessData[Index]; 98 | hProcessSnap := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); 99 | if (hProcessSnap = INVALID_HANDLE_VALUE) then Exit; 100 | try 101 | FillChar(ProcessEntry, SizeOf(TProcessEntry32), #0); 102 | ProcessEntry.dwSize := SizeOf(TProcessEntry32); 103 | if not Process32First(hProcessSnap, ProcessEntry) then Exit; 104 | repeat 105 | if FProcessData.IndexOfObject( 106 | Pointer(ProcessEntry.th32ProcessID)) >= 0 then Continue; 107 | if GetProcessFullPath(ProcessEntry.th32ProcessID) = ProcessName then 108 | begin 109 | FProcessData.AddObject(ProcessName, Pointer(ProcessEntry.th32ProcessID)); 110 | Result := ProcessEntry.th32ProcessID; 111 | Break; 112 | end; 113 | until not Process32Next(hProcessSnap, ProcessEntry); 114 | finally 115 | CloseHandle(hProcessSnap); 116 | end; 117 | end; 118 | 119 | procedure TProcessReconnect.SetKnownProcessList(Value: TStringList); 120 | begin 121 | FProcessData.Assign(Value); 122 | end; 123 | 124 | initialization 125 | 126 | finalization 127 | 128 | _ProcessReconnect.Free; 129 | 130 | end. 131 | -------------------------------------------------------------------------------- /win64debug.rc: -------------------------------------------------------------------------------- 1 | PE64_IMAGE RCDATA ".\win64\debug\processmm.exe" -------------------------------------------------------------------------------- /win64release.rc: -------------------------------------------------------------------------------- 1 | PE64_IMAGE RCDATA ".\win64\release\processmm.exe" 2 | --------------------------------------------------------------------------------