-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathMemoryTool.cls
More file actions
131 lines (114 loc) · 4.78 KB
/
Copy pathMemoryTool.cls
File metadata and controls
131 lines (114 loc) · 4.78 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
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
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
VERSION 1.0 CLASS
BEGIN
MultiUse = -1 'True
END
Attribute VB_Name = "MemoryTool"
Attribute VB_GlobalNameSpace = False
Attribute VB_Creatable = False
Attribute VB_PredeclaredId = False
Attribute VB_Exposed = False
Option Explicit
Private Type MEMORY_BASIC_INFORMATION
BaseAddress As LongPtr
AllocationBase As LongPtr
AllocationProtect As Long
PartitionId As Integer
RegionSize As LongPtr
State As Long
Protect As Long
Type As Long
End Type
Private Declare PtrSafe Function GetModuleInformation Lib "psapi" (ByVal hProcess As LongPtr, ByVal hModule As LongPtr, ByRef lpModInfo As MODULEINFO, cb As Long) As Long
Private Declare PtrSafe Function GetCurrentProcess Lib "kernel32" () As LongPtr
Private Declare PtrSafe Function GetModuleHandle Lib "kernel32" Alias "GetModuleHandleA" (ByVal lpModuleName As String) As LongPtr
Private Declare PtrSafe Sub RtlMoveMemory Lib "kernel32" (ByRef destination As Any, ByVal lpSource As LongPtr, ByVal size As Long)
Private Declare PtrSafe Function VirtualQueryEx Lib "kernel32" (ByVal hProcess As LongPtr, ByVal lpAddress As LongPtr, ByRef MemoryInformation As MEMORY_BASIC_INFORMATION, ByVal dwLength As Long) As Long
Private mMemoryRange() As MEMORY_BASIC_INFORMATION
Private mMemoryRangeCount As Long
Private MemoryRangeSize As Long
Private mSessionId As String
Private mhProcess As LongPtr
Private mPageSize As Long
Private Sub Class_Initialize()
ReDim mMemoryRange(0 To &HF)
MemoryRangeSize = LenB(mMemoryRange(0))
mhProcess = GetCurrentProcess()
mSessionId = vbNullChar
mPageSize = &H1000
End Sub
Public Sub StartSession(SessionId As String)
If SessionId <> mSessionId Then
PurgeSessionData
End If
mSessionId = SessionId
End Sub
Public Sub EndSession()
PurgeSessionData
mSessionId = vbNullChar
End Sub
Private Sub PurgeSessionData()
mMemoryRangeCount = 0
ReDim mMemoryRange(0 To &HF)
End Sub
Private Function IsValidPointer(ByVal lpAddress As LongPtr) As Boolean
Dim i As Long, rangeCount As Long
'Null pointers are the most common exception...
If lpAddress = 0 Then Exit Function
'Inherently invalid addresses don't need to be checked
#If Win64 Then
If lpAddress And &H8000000000000000^ Then Exit Function
#Else
If lpAddress And &H80000000 Then Exit Function
#End If
Dim thisMemoryRange As MEMORY_BASIC_INFORMATION
If mSessionId = vbNullChar Then
If VirtualQueryEx(mhProcess, lpAddress, thisMemoryRange, MemoryRangeSize) Then
IsValidPointer = True
Else
IsValidPointer = False
End If
Exit Function
End If
'Of course this doesn't take memory deallocations into account....
For i = 0 To mMemoryRangeCount - 1
'In C this wouldn't work because of how the compiler simplifies pointer arithmatic... but we don't have to worry about it here.
If lpAddress >= mMemoryRange(i).AllocationBase And lpAddress < (mMemoryRange(i).AllocationBase + mMemoryRange(i).RegionSize) Then
IsValidPointer = True
Exit Function
End If
Next
rangeCount = UBound(mMemoryRange)
If mMemoryRangeCount >= rangeCount Then
rangeCount = rangeCount + &H10
ReDim Preserve mMemoryRange(0 To rangeCount)
End If
If VirtualQueryEx(mhProcess, lpAddress, mMemoryRange(mMemoryRangeCount), MemoryRangeSize) Then
mMemoryRangeCount = mMemoryRangeCount + 1
IsValidPointer = True
Exit Function
Else
IsValidPointer = False
End If
End Function
Public Sub FollowPointer(ByVal lpTarget As LongPtr, ByVal lpSource As LongPtr, ByVal size As Long, Optional ThrowOnSourceExceedsPageError As Boolean = True)
If Not (IsValidPointer(lpSource)) Then
Err.Raise INVALID_PROCEDURE_CALL_OR_ARGUMENT, "MemoryTool.FollowPointer", "The source pointer 0x" & Hex(lpSource) & " is not a valid pointer."
ElseIf Not (IsValidPointer(lpTarget)) Then
Err.Raise INVALID_PROCEDURE_CALL_OR_ARGUMENT, "MemoryTool.FollowPointer", "The target pointer 0x" & Hex(lpTarget) & " is not a valid pointer."
Else
If ((lpTarget Mod mPageSize) + size) > mPageSize Then
If Not (IsValidPointer(lpTarget + size)) Then
Err.Raise INVALID_PROCEDURE_CALL_OR_ARGUMENT, "MemoryTool.FollowPointer", "The memory size 0x" & Hex(size) & " is invalid at address 0x" & Hex(lpTarget) & "."
End If
ElseIf ((lpSource Mod mPageSize) + size) > mPageSize Then
If Not (IsValidPointer(lpSource + size)) Then
If ThrowOnSourceExceedsPageError Then
Err.Raise INVALID_PROCEDURE_CALL_OR_ARGUMENT, "MemoryTool.FollowPointer", "The memory size 0x" & Hex(size) & " is invalid at address 0x" & Hex(lpSource) & "."
Else
size = mPageSize - CLng(lpSource Mod mPageSize)
End If
End If
End If
End If
RtlMoveMemory ByVal lpTarget, lpSource, size
End Sub