Skip to content

Commit 26f7d20

Browse files
committed
Changed string detection.
Fixed memory out of range reads.
1 parent 6d3c870 commit 26f7d20

File tree

4 files changed

+89
-40
lines changed

4 files changed

+89
-40
lines changed

Memory/Memory.cs

Lines changed: 32 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -67,24 +67,29 @@ public byte ReadByte(IntPtr offset)
6767

6868
public byte ReadByte(int offset)
6969
{
70-
if (Offset + offset < 0 || Offset + offset > data.Length)
70+
Contract.Requires(offset >= 0);
71+
72+
if (Offset + offset > data.Length)
7173
{
72-
throw new IndexOutOfRangeException();
74+
return 0;
7375
}
7476

7577
return data[Offset + offset];
7678
}
7779

7880
public byte[] ReadBytes(int offset, int length)
7981
{
80-
if (Offset + offset < 0 || Offset + offset + length > data.Length)
82+
Contract.Requires(offset >= 0);
83+
84+
var bytes = new byte[length];
85+
86+
if (Offset + offset + length > data.Length)
8187
{
82-
throw new IndexOutOfRangeException();
88+
return bytes;
8389
}
8490

85-
var b = new byte[length];
86-
Array.Copy(data, Offset + offset, b, 0, length);
87-
return b;
91+
Array.Copy(data, Offset + offset, bytes, 0, length);
92+
return bytes;
8893
}
8994

9095
public T ReadObject<T>(IntPtr offset) where T : struct
@@ -94,6 +99,13 @@ public T ReadObject<T>(IntPtr offset) where T : struct
9499

95100
public T ReadObject<T>(int offset) where T : struct
96101
{
102+
Contract.Requires(offset >= 0);
103+
104+
if (Offset + offset + Marshal.SizeOf(typeof(T)) > data.Length)
105+
{
106+
return default(T);
107+
}
108+
97109
var handle = GCHandle.Alloc(data, GCHandleType.Pinned);
98110
var obj = (T)Marshal.PtrToStructure(handle.AddrOfPinnedObject() + Offset + offset, typeof(T));
99111
handle.Free();
@@ -112,16 +124,18 @@ public string ReadPrintableASCIIString(IntPtr offset, int length)
112124
public string ReadPrintableASCIIString(int offset, int length)
113125
{
114126
Contract.Requires(offset >= 0);
115-
//Contract.Requires(offset < data.Length);
116127
Contract.Requires(length >= 0);
117-
//Contract.Requires(length < data.Length);
118-
//Contract.Requires(offset + length < data.Length);
119128
Contract.Ensures(Contract.Result<string>() != null);
120129

130+
if (Offset + offset + length > data.Length)
131+
{
132+
length = data.Length - Offset - offset;
133+
}
134+
121135
var sb = new StringBuilder(length);
122136
for (var i = 0; i < length; ++i)
123137
{
124-
var c = (char)data[offset + i];
138+
var c = (char)data[Offset + offset + i];
125139
sb.Append(c.IsPrintable() ? c : '.');
126140
}
127141
return sb.ToString();
@@ -130,8 +144,15 @@ public string ReadPrintableASCIIString(int offset, int length)
130144
private string ReadString(Encoding encoding, int offset, int length)
131145
{
132146
Contract.Requires(encoding != null);
147+
Contract.Requires(offset >= 0);
148+
Contract.Requires(length >= 0);
133149
Contract.Ensures(Contract.Result<string>() != null);
134150

151+
if (Offset + offset + length > data.Length)
152+
{
153+
length = data.Length - Offset - offset;
154+
}
155+
135156
var sb = new StringBuilder(encoding.GetString(data, offset, length));
136157
for (var i = 0; i < sb.Length; ++i)
137158
{

Memory/NodeDissector.cs

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -41,15 +41,15 @@ public static Type GuessType(BaseHexNode node, MemoryBuffer memory)
4141
var data64 = memory.ReadObject<UInt64FloatDoubleData>(offset);
4242
var data32 = memory.ReadObject<UInt32FloatData>(offset);
4343

44-
/*var raw = memory.ReadBytes(offset, node.MemorySize);
45-
if (raw.IsPrintableData())
44+
var raw = memory.ReadBytes(offset, node.MemorySize);
45+
if (raw.InterpretAsUTF8().IsPrintableData())
4646
{
4747
return typeof(UTF8TextNode);
4848
}
49-
else if (raw.EveryNth(2).IsPrintableData())
49+
else if (raw.InterpretAsUTF16().IsPrintableData())
5050
{
5151
return typeof(UTF16TextNode);
52-
}*/
52+
}
5353

5454
if (is8ByteAligned)
5555
{
@@ -139,18 +139,14 @@ private static Type GuessPointerType(IntPtr address, MemoryBuffer memory)
139139

140140
// Check if it is a string.
141141
var data = memory.Process.ReadRemoteMemory(address, IntPtr.Size);
142-
if (data.IsPrintableData())
142+
if (data.InterpretAsUTF8().IsPrintableData())
143143
{
144144
return typeof(UTF8TextPtrNode);
145145
}
146-
else if (data.EveryNth(2).IsPrintableData())
146+
else if (data.InterpretAsUTF16().IsPrintableData())
147147
{
148148
return typeof(UTF16TextPtrNode);
149149
}
150-
/*else if (!data.EveryNth(4).Where(b => !((char)b).IsPrintable()).Any())
151-
{
152-
return typeof(UTF32TextPtrNode);
153-
}*/
154150

155151
// Now it could be a pointer to something else but we can't tell. :(
156152
//return typeof(ClassPtrNode);

Nodes/BaseHexCommentNode.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,12 +70,12 @@ protected int AddComment(ViewInfo view, int x, int y, float fvalue, IntPtr ivalu
7070
var data = view.Memory.Process.ReadRemoteMemory(ivalue, 64);
7171

7272
// First check if it could be an UTF8 string and if not try UTF16.
73-
if (data.Take(IntPtr.Size).IsPrintableData())
73+
if (data.Take(IntPtr.Size).InterpretAsUTF8().IsPrintableData())
7474
{
7575
var text = new string(Encoding.UTF8.GetChars(data).TakeWhile(c => c != 0).ToArray());
7676
x = AddText(view, x, y, Program.Settings.TextColor, HotSpot.NoneId, $"'{text}'") + view.Font.Width;
7777
}
78-
else if(data.EveryNth(2).Take(IntPtr.Size).IsPrintableData())
78+
else if(data.Take(IntPtr.Size * 2).InterpretAsUTF16().IsPrintableData())
7979
{
8080
var text = new string(Encoding.Unicode.GetChars(data).TakeWhile(c => c != 0).ToArray());
8181
x = AddText(view, x, y, Program.Settings.TextColor, HotSpot.NoneId, $"L'{text}'") + view.Font.Width;

Util/Extensions.cs

Lines changed: 49 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -142,9 +142,56 @@ public static bool IsPrintable(this char c)
142142
return ' ' <= c && c <= '~';
143143
}
144144

145-
public static bool IsPrintableData(this IEnumerable<byte> source)
145+
public static IEnumerable<char> InterpretAsUTF8(this IEnumerable<byte> source)
146146
{
147-
return source.All(b => ((char)b).IsPrintable());
147+
Contract.Requires(source != null);
148+
149+
return source.Select(b => (char)b);
150+
}
151+
152+
public static IEnumerable<char> InterpretAsUTF16(this IEnumerable<byte> source)
153+
{
154+
Contract.Requires(source != null);
155+
156+
var bytes = source.ToArray();
157+
var chars = new char[bytes.Length / 2];
158+
Buffer.BlockCopy(bytes, 0, chars, 0, bytes.Length);
159+
return chars;
160+
}
161+
162+
public static bool IsPrintableData(this IEnumerable<char> source)
163+
{
164+
Contract.Requires(source != null);
165+
166+
return IsLikelyPrintableData(source) >= 0.75f;
167+
}
168+
169+
public static float IsLikelyPrintableData(this IEnumerable<char> source)
170+
{
171+
Contract.Requires(source != null);
172+
173+
bool doCountValid = true;
174+
int countValid = 0;
175+
int countAll = 0;
176+
177+
foreach (var c in source)
178+
{
179+
countAll++;
180+
181+
if (doCountValid)
182+
{
183+
if (c.IsPrintable())
184+
{
185+
countValid++;
186+
}
187+
else
188+
{
189+
doCountValid = false;
190+
}
191+
}
192+
}
193+
194+
return countValid / (float)countAll;
148195
}
149196

150197
[Pure]
@@ -253,21 +300,6 @@ public static IEnumerable<TSource> Traverse<TSource>(this IEnumerable<TSource> s
253300
}
254301
}
255302

256-
public static IEnumerable<TSource> EveryNth<TSource>(this IEnumerable<TSource> source, int n)
257-
{
258-
Contract.Requires(source != null);
259-
Contract.Requires(n > 0);
260-
261-
int i = 0;
262-
foreach (var item in source)
263-
{
264-
if (i++ % n == 0)
265-
{
266-
yield return item;
267-
}
268-
}
269-
}
270-
271303
public static IEnumerable<TSource> SkipUntil<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate)
272304
{
273305
Contract.Requires(source != null);

0 commit comments

Comments
 (0)