Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions OmsiExtensions.sln
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TriggersSample", "_OmsiHook
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "VideoDemo", "_OmsiHookExamples\VideoDemo\VideoDemo.csproj", "{D94FF6D3-08AA-41CB-B9B9-F82E860E6E96}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ClickablePlaneDemo", "_OmsiHookExamples\ClickablePlaneDemo\ClickablePlaneDemo.csproj", "{49428923-732C-4541-8C97-C6D9C004D726}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ClickablePlaneDemo", "_OmsiHookExamples\ClickablePlaneDemo\ClickablePlaneDemo.csproj", "{49428923-732C-4541-8C97-C6D9C004D726}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Expand Down Expand Up @@ -97,8 +97,8 @@ Global
{CBCB99EF-DD1A-4D4D-A9A8-9BF251FDCD1B}.ReleaseAndDocs|Any CPU.Build.0 = Release|Win32
{CBCB99EF-DD1A-4D4D-A9A8-9BF251FDCD1B}.ReleaseAndDocs|x86.ActiveCfg = Release|Win32
{CBCB99EF-DD1A-4D4D-A9A8-9BF251FDCD1B}.ReleaseAndDocs|x86.Build.0 = Release|Win32
{CDB17143-5653-48BE-AAC8-8419D5B4FD2C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{CDB17143-5653-48BE-AAC8-8419D5B4FD2C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{CDB17143-5653-48BE-AAC8-8419D5B4FD2C}.Debug|Any CPU.ActiveCfg = Debug|x86
{CDB17143-5653-48BE-AAC8-8419D5B4FD2C}.Debug|Any CPU.Build.0 = Debug|x86
{CDB17143-5653-48BE-AAC8-8419D5B4FD2C}.Debug|x86.ActiveCfg = Debug|x86
{CDB17143-5653-48BE-AAC8-8419D5B4FD2C}.Debug|x86.Build.0 = Debug|x86
{CDB17143-5653-48BE-AAC8-8419D5B4FD2C}.Release|Any CPU.ActiveCfg = Release|Any CPU
Expand Down
2 changes: 2 additions & 0 deletions OmsiHook/FastBinaryWriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@

namespace OmsiHook;

#pragma warning disable CS9191

internal static class FastBinaryWriter
{
public static void Write(Span<byte> buffer, ref int pos, int data)
Expand Down
2 changes: 1 addition & 1 deletion OmsiHook/MemArray/MemArrayString.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public override string this[int index]
{
if (cached)
arrayCache[index] = value;
Memory.WriteMemoryArrayItemSafe(Address, Memory.AllocateString(value).Result, index);
Memory.WriteMemoryArrayItemSafe(Address, Memory.AllocateString(value, wide).Result, index);
}
}

Expand Down
6 changes: 3 additions & 3 deletions OmsiHook/MemArray/MemArrayStringDict.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ namespace OmsiHook
/// </remarks>
public class MemArrayStringDict : MemArrayString
{
private Dictionary<string, int> indexDictionary = new();
private readonly Dictionary<string, int> indexDictionary = [];

public Dictionary<string, int> IndexDictionary => indexDictionary;

Expand Down Expand Up @@ -58,8 +58,8 @@ public override void UpdateFromHook(int index = -1)
public override int IndexOf(string item) => indexDictionary[item];
public override bool Remove(string item)
{
if (indexDictionary.ContainsKey(item))
base.RemoveAt(indexDictionary[item]);
if (indexDictionary.TryGetValue(item, out var ind))
base.RemoveAt(ind);
else
return false;
return true;
Expand Down
108 changes: 90 additions & 18 deletions OmsiHook/Memory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
using System.Threading;
using System.Threading.Tasks;

#pragma warning disable CS9191

namespace OmsiHook
{
/// <summary>
Expand Down Expand Up @@ -118,7 +120,7 @@ public void WriteMemory<T>(int address, T value) where T : unmanaged

var size = StructureToByteArray(value, writeBuffer.Value, 0);

if (!Imports.WriteProcessMemory((int)omsiProcessHandle, address, writeBuffer.Value, size, out _))
if (!Imports.WriteProcessMemory(unchecked((int)omsiProcessHandle), address, writeBuffer.Value, size, out _))
throw new MemoryAccessException($"Couldn't write {Unsafe.SizeOf<T>()} bytes of process memory @ 0x{address:X8}!", address);
}

Expand Down Expand Up @@ -469,6 +471,10 @@ internal int AllocateStruct<T>(object value, int references = 1) where T : unman
/// <exception cref="NotImplementedException">Writing to raw strings is not yet supported.</exception>
public async Task<int> AllocateString(string value, bool wide = false, int references = 1, bool raw = false)
{
// TODO: What does "raw" actually mean in this context, should it return a pointer to (string + 0xc)?
// Previously the raw paramter was completely ignored and nothing needed it so we need to do some
// research to find out if it's actually needed.
// Once raw string allocation is implemented, remember to update callers of this method to use it.
/*
* AnsiString/UnicodeString struct layout:
* 0 - / Code page (short)
Expand Down Expand Up @@ -712,18 +718,55 @@ public string ReadMemoryString(int address, bool wide = false, bool raw = false,
if (wide)
strLen *= 2;
var bytes = ReadMemory(i, (int)strLen, readBuffer.Value);
ret = wide ? new string(MemoryMarshal.Cast<byte, char>(bytes)) : Encoding.ASCII.GetString(bytes);
ret = wide ? new(MemoryMarshal.Cast<byte, char>(bytes)) : Encoding.ASCII.GetString(bytes.Array, bytes.Offset, bytes.Count);
}
else
{
var sb = new StringBuilder();
using var sb = new PooledStringBuilder();
try
{
// Cache the read buffer to save a few checks (that the compiler would probably have hoisted out anyway)
var readBuff = readBuffer.Value;
//int readSize = 16;
// TODO: Rewrite this to read chunks of memory all at once instead of one char at a time...
int readSize = 16;
int endPos = i | readSize;
while (true)
{
// Read aligned chunks of bytes, we're unlikely to cause an illegal access if we align our reads
int len = Math.Max(i - endPos + 1, wide ? 2 : 1);
var bytes = ReadMemory(i, len, readBuff).AsSpan();
if (bytes.IsEmpty)
break;
int nullPos = len;
if (wide)
{
// Wide strings are blittable to c# strings
var chars = MemoryMarshal.Cast<byte, char>(bytes);
// Check if we've reached the end of the string
int p = chars.IndexOf((char)0);
if (p > 0)
nullPos = p;

sb.Append(chars[0..p]);
}
else
{
int p = bytes.IndexOf((byte)0);
if (p > 0)
nullPos = p;

// Expand each ascii char into a utf16 char (this is not necessarily a correct conversion)
for (int j = 0; j < nullPos; j++)
sb.Append((char)bytes[j]);
}
if (nullPos != len)
break;

i += len;
endPos = i | readSize;
}

// TODO: Rewrite this to read chunks of memory all at once instead of one char at a time...
/*while (true)
{
var bytes = ReadMemory(i, wide ? 2 : 1, readBuff);
if (bytes.Count == 0 || (wide ? (bytes[0] | bytes[1]) : bytes[0]) == 0)
Expand All @@ -734,7 +777,7 @@ public string ReadMemoryString(int address, bool wide = false, bool raw = false,
i++;
if (wide)
i++;
}
}*/
}
catch (MemoryAccessException) { return null; }
ret = sb.ToString();
Expand Down Expand Up @@ -1099,11 +1142,11 @@ public OutStruct MarshalStruct<OutStruct, InStruct>(InStruct obj)
try
{
#endif
var native = f.native.GetValueDirect(objRef);
if (f.toLocal != null)
f.local.SetValueDirect(retRef, f.toLocal(native));
else
f.local.SetValueDirect(retRef, native);
var native = f.native.GetValueDirect(objRef);
if (f.toLocal != null)
f.local.SetValueDirect(retRef, f.toLocal(native));
else
f.local.SetValueDirect(retRef, native);
#if DEBUG
}
catch (Exception ex)
Expand Down Expand Up @@ -1162,11 +1205,11 @@ public OutStruct UnMarshalStruct<OutStruct, InStruct>(InStruct obj)
try
{
#endif
var local = f.local.GetValueDirect(objRef);
if (f.toLocal != null)
f.native.SetValueDirect(retRef, f.toNative(local));
else
f.native.SetValueDirect(retRef, local);
var local = f.local.GetValueDirect(objRef);
if (f.toLocal != null)
f.native.SetValueDirect(retRef, f.toNative(local));
else
f.native.SetValueDirect(retRef, local);
#if DEBUG
}
catch (Exception ex)
Expand Down Expand Up @@ -1300,10 +1343,38 @@ public void Dispose()
#endregion
}

internal static class Imports
internal static partial class Imports
{
#region DllImports

#if NET7_0_OR_GREATER
[LibraryImport("kernel32.dll")]
public static partial IntPtr OpenProcess(int dwDesiredAccess, [MarshalAs(UnmanagedType.Bool)] bool bInheritHandle, int dwProcessId);
[LibraryImport("kernel32.dll")]
public static partial IntPtr CloseHandle(IntPtr handle);

[LibraryImport("kernel32.dll")]
[return:MarshalAs(UnmanagedType.Bool)] public static partial bool ReadProcessMemory(int hProcess, int lpBaseAddress, byte[] buffer, int size, ref int lpNumberOfBytesRead);

[LibraryImport("kernel32.dll")]
[return: MarshalAs(UnmanagedType.Bool)] public static partial bool WriteProcessMemory(int hProcess, int lpBaseAddress, byte[] buffer, int size, out int lpNumberOfBytesWritten);
[LibraryImport("kernel32.dll")]
[return: MarshalAs(UnmanagedType.Bool)] public static partial bool WriteProcessMemory(int hProcess, int lpBaseAddress, ref byte buffer, int size, out int lpNumberOfBytesWritten);

/// <summary>
/// Allocates memory in a remote process's memory space.
/// </summary>
/// <param name="hProcess">The pointer to the process to allocate memory in</param>
/// <param name="lpAddress">The desired starting address to allocate memory at (leave at 0 for default)</param>
/// <param name="dwSize">How many bytes of memory to allocate</param>
/// <param name="flAllocationType">The type of allocation</param>
/// <param name="flProtect">The type of memory protection for the regions to be allocated</param>
/// <returns>The address of the allocated memory. Returns 0 if the allocation failed.</returns>
[LibraryImport("kernel32.dll")]
public static partial int VirtualAllocEx(int hProcess, int lpAddress, int dwSize, AllocationType flAllocationType, MemoryProtectionType flProtect);
[LibraryImport("kernel32.dll")]
[return: MarshalAs(UnmanagedType.Bool)] public static partial bool VirtualFreeEx(int hProcess, int lpAddress, int dwSize, FreeType dwFreeType);
#else
[DllImport("kernel32.dll")]
public static extern IntPtr OpenProcess(int dwDesiredAccess, bool bInheritHandle, int dwProcessId);
[DllImport("kernel32.dll")]
Expand All @@ -1330,7 +1401,8 @@ internal static class Imports
public static extern int VirtualAllocEx(int hProcess, int lpAddress, int dwSize, AllocationType flAllocationType, MemoryProtectionType flProtect);
[DllImport("kernel32.dll")]
public static extern bool VirtualFreeEx(int hProcess, int lpAddress, int dwSize, FreeType dwFreeType);
#endregion
#endif
#endregion

[Flags]
internal enum AllocationType : int
Expand Down
37 changes: 21 additions & 16 deletions OmsiHook/OmsiHook.csproj
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net6.0-windows</TargetFramework>
<!--<TargetFrameworks>net6.0-windows;net7.0-windows;net8.0-windows;net9.0-windows;net10.0-windows</TargetFrameworks>-->
<TargetFrameworks>net6.0-windows;net7.0-windows;net8.0-windows</TargetFrameworks>
<RuntimeIdentifier>win-x86</RuntimeIdentifier>
<Authors>Thomas Mathieson et al</Authors>
<Copyright>Copyright Thomas Mathieson 2022-2024 all rights reserved</Copyright>
<PackageProjectUrl>https://github.com/space928/Omsi-Extensions</PackageProjectUrl>
Expand All @@ -10,15 +12,16 @@
<Description>OmsiHook is a simple library for hooking into Omsi's memory for modding.</Description>
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<AssemblyVersion>2.5.3.1</AssemblyVersion>
<FileVersion>2.5.3.1</FileVersion>
<Version>2.5.3</Version>
<AssemblyVersion>2.5.4.1</AssemblyVersion>
<FileVersion>2.5.4.1</FileVersion>
<Version>2.5.4</Version>
<PackageLicenseExpression>LGPL-3.0-only</PackageLicenseExpression>
<SignAssembly>False</SignAssembly>
<PackageReadmeFile>README.md</PackageReadmeFile>
<PackageIcon>Logo.png</PackageIcon>
<IncludeSymbols>true</IncludeSymbols>
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
<LangVersion>12</LangVersion>
<Nullable>disable</Nullable>
<Platforms>x86</Platforms>
<GenerateDocumentationFile>False</GenerateDocumentationFile>
Expand Down Expand Up @@ -70,32 +73,32 @@
<None Include="..\$(_ConfigurationNormalized)\OmsiHookInvoker.dll" Link="OmsiHookInvoker.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<Pack>True</Pack>
<PackagePath>\lib\net6.0-windows7.0</PackagePath>
<PackagePath>\lib\$(TargetFramework)</PackagePath>
</None>
<None Include="..\OmsiHookRPCPlugin\bin\x86\$(_ConfigurationNormalized)\$(TargetFramework)\OmsiHookRPCPlugin.dll" Link="OmsiHookRPCPlugin.dll">
<None Include="..\OmsiHookRPCPlugin\bin\x86\$(_ConfigurationNormalized)\netstandard2.0\win-x86\OmsiHookRPCPlugin.dll" Link="OmsiHookRPCPlugin.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<Pack>True</Pack>
<PackagePath>\lib\net6.0-windows7.0</PackagePath>
<PackagePath>\lib\$(TargetFramework)</PackagePath>
</None>
<None Include="..\OmsiHookRPCPlugin\bin\x86\$(_ConfigurationNormalized)\$(TargetFramework)\OmsiHookRPCPlugin.deps.json" Link="OmsiHookRPCPlugin.deps.json">
<None Include="..\OmsiHookRPCPlugin\bin\x86\$(_ConfigurationNormalized)\netstandard2.0\win-x86\OmsiHookRPCPlugin.deps.json" Link="OmsiHookRPCPlugin.deps.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<Pack>True</Pack>
<PackagePath>\lib\net6.0-windows7.0</PackagePath>
<PackagePath>\lib\$(TargetFramework)</PackagePath>
</None>
<None Include="..\OmsiHookRPCPlugin\bin\x86\$(_ConfigurationNormalized)\$(TargetFramework)\OmsiHookRPCPlugin.runtimeconfig.json" Link="OmsiHookRPCPlugin.runtimeconfig.json">
<!--<None Include="..\OmsiHookRPCPlugin\bin\x86\$(_ConfigurationNormalized)\netstandard2.0\win-x86\OmsiHookRPCPlugin.runtimeconfig.json" Link="OmsiHookRPCPlugin.runtimeconfig.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<Pack>True</Pack>
<PackagePath>\lib\net6.0-windows7.0</PackagePath>
</None>
<None Include="..\OmsiHookRPCPlugin\bin\x86\$(_ConfigurationNormalized)\$(TargetFramework)\OmsiHookRPCPluginNE.dll" Link="OmsiHookRPCPluginNE.dll">
<PackagePath>\lib\$(TargetFramework)</PackagePath>
</None>-->
<None Include="..\OmsiHookRPCPlugin\bin\x86\$(_ConfigurationNormalized)\netstandard2.0\win-x86\OmsiHookRPCPluginNE.dll" Link="OmsiHookRPCPluginNE.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<Pack>True</Pack>
<PackagePath>\lib\net6.0-windows7.0</PackagePath>
<PackagePath>\lib\$(TargetFramework)</PackagePath>
</None>
<None Include="..\OmsiHookRPCPlugin\bin\x86\$(_ConfigurationNormalized)\$(TargetFramework)\OmsiHookRPCPlugin.opl" Link="OmsiHookRPCPlugin.opl">
<None Include="..\OmsiHookRPCPlugin\bin\x86\$(_ConfigurationNormalized)\netstandard2.0\win-x86\OmsiHookRPCPlugin.opl" Link="OmsiHookRPCPlugin.opl">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<Pack>True</Pack>
<PackagePath>\lib\net6.0-windows7.0</PackagePath>
<PackagePath>\lib\$(TargetFramework)</PackagePath>
</None>
</ItemGroup>

Expand All @@ -106,6 +109,8 @@
<GeneratePathProperty>True</GeneratePathProperty>
</PackageReference>
<PackageReference Include="memberpage" Version="2.59.4" />
<PackageReference Include="System.Runtime.CompilerServices.Unsafe" Version="6.1.2" />
<PackageReference Include="System.Runtime.Numerics" Version="4.3.0" />
</ItemGroup>

<ItemGroup>
Expand Down
Loading
Loading