I am creating a directx overlay for an esp hack in a game. (I have made several in C++ but wanted to try c#) This method requires me to use a version of directx which is only compatible with .net framework 3.5 or older. I have been using this code to obtain the base address of a specific module:
static int GetModuleAddress(string moduleName)
{
try
{
Process[] p = Process.GetProcessesByName(game.process);
if (p.Length > 0)
{
foreach (ProcessModule m in p[0].Modules)
{
if (m.ModuleName == moduleName)
{
//temp = (int)m.BaseAddress;
//return temp;
return (int)m.BaseAddress;
}
}
return -1;
}
else
{
return -1;
}
}
catch (Exception ex)
{
return -1;
}
}
This code works fine in framework 4.5.2 (it cycles through nearly 100 different modules and returns the base address of whichever module i'm looking for). But when using the code in 3.5 it only cycles through about 5 modules (none of which are the ones i need) and returns -1.
Why is this caused? Is there another way to obtain a base address of a module?
The reason you're only seeing 5 modules is because you're using an x86 program to parse the modules of an x64 process. If you're making a program that interacts with the memory of an external process you should always compile it for the target processes's architecture. This will save you lots of headache.
Use IntPtr for addresses and offsets and compile both x86 and x64 versions, then use the correct version for each type of target process, this will ensure the minimal amount of problems.
In addition, make sure you always run as administrator.
Related
I have a c# library which provides some functionallity to upload data onto connected (android) devices. The dll itself gets exported via UnmangedExports to be used by an delphi application.
Here is the function which gets called by the delphi application:
[DllExport]
[return: MarshalAs(UnmanagedType.LPStr)]
public static string getDevices()
{
try
{
var devices = string.Empty;
var collection = new PortableDeviceCollection();
collection.Refresh();
foreach (var device in collection)
{
device.Connect();
if (devices != string.Empty)
{
devices += ";";
}
devices += device.FriendlyName;
device.Disconnect();
}
return devices;
}
catch (Exception e)
{
SomeClass.WriteErrorToLogFile(e);
return "ERROR";
}
}
Here is the class PortableDeviceCollection:
public class PortableDeviceCollection : Collection<PortableDevice>
{
private readonly PortableDeviceApiLib.PortableDeviceManagerClass _deviceManager;
public PortableDeviceCollection()
{
this._deviceManager = new PortableDeviceApiLib.PortableDeviceManagerClass();
}
public bool Refresh()
{
this._deviceManager.RefreshDeviceList();
// Determine how many WPD devices are connected
var deviceIds = new string[1];
uint count = 1;
this._deviceManager.GetDevices(null, ref count);
if (count > 0)
{
// Retrieve the device id for each connected device
deviceIds = new string[count];
this._deviceManager.GetDevices(deviceIds, ref count);
foreach (var deviceId in deviceIds)
{
Add(new PortableDevice(deviceId));
}
return true;
}
else
return false;
}
}
I can create the dll with visual studio and use this inside of the delphi application. When the delphi application calls the getDevices() function, i get an error on the instantiation of the PortableDeviceCollection class:
The file or assembly "Interop.PortableDeviceApiLib, Version = 1.0.0.0,
Culture = neutral, PublicKeyToken = null" or a dependency of it was
not found. The assembly is created by a runtime that is more recent
than the currently loaded runtime and can not be loaded.
ProductXY.PortableDeviceCollection..ctor()
ProductXY.ProductXYMain.getDevices()
The targetframework for the c# project is set to .Net Framework 4. Using any lower version i get an error when i try to compile the project:
The primary reference "Interop.PortableDeviceApiLib" could not be
resolved because it has an indirect dependency on the .NET Framework
assembly "mscorlib, version = 4.0.0.0, Culture = neutral,
PublicKeyToken = b77a5c561934e089", which is a higher version 4.0.0.0
than version 2.0.0.0 in the current target framework.
Please note. I have neither written the c# library nor the delphi application. Both have worked together for years. Now i have to add a functionallity to the c# library. I have not added any code to the project. I just tried to compile it again and use the dll. The only thing i did was updating the RGiesecke.DLLExport.Metadata via NuGet Packetmanager. Without updating i got an error
"Microsoft.Build.Utilities.ToolLocationHelper could not find
ildasm.exe"
I am aware of this Enumerating Windows Portable Devices in C# question. But my error is thrown before the code which is treaded by the question is reached. I still tried the solution to the question, but the action (deassamble, find and replace in the dll) which is described in the answere has already been done (otherwise my code would not have compiled).
The error message doesn't make sense to me. Interop.PortableDeviceApiLib is a COM-Lib which is not available for download in different framework-versions. I think I am missing something here.
Can anyone help me?
I was finally able to solve this problem. To be honest I don't know what finally solved this. For every one who stumbles up on this, here are the things i tried to fix this problem. They are in no specific order (since i tried everything multiple times):
Updating the RGiesecke.DLLExport packet
Changing the plattform in the Konfigurations-Manager to x86
Disassamble, edit and reassable the Interop.PortableDeviceApiLib like in this question (answeres of Christophe Geers and Bruno Klein)
Delete the reference to the Interop.PortableDeviceApiLib
Delete the reference to the Interop.PortableDeviceTypesLib
Readding the reference to the Interop.PortableDeviceApiLib
Readding the reference to the Interop.PortableDeviceTypesLib
Rebuild the project
Setting the Interoptyp embeddet on both to false (I found various statements to NOT do this, but the project was set up like this when i got it and it worked (be carefull)) on both Interop-Libs.
At least this helped me.
I have a 32bit dll (no source code) that I need to access from 64bit C# application. I've read this article and took a look into the corresponding code from here. I've also read this post.
I'm not sure that I'm asking the right question, so please help me.
There are 3 projects: dotnetclient, x86Library and x86x64. The x86x64 has x86LibraryProxy.cpp which loads the x86library.dll and calls the GetTemperature function:
STDMETHODIMP Cx86LibraryProxy::GetTemperature(ULONG sensorId, FLOAT* temperature)
{
*temperature = -1;
typedef float (__cdecl *PGETTEMPERATURE)(int);
PGETTEMPERATURE pFunc;
TCHAR buf[256];
HMODULE hLib = LoadLibrary(L"x86library.dll");
if (hLib != NULL)
{
pFunc = (PGETTEMPERATURE)GetProcAddress(hLib, "GetTemperature");
if (pFunc != NULL)
dotnetclient calls that GetTemperature function and print the result:
static void Main(string[] args)
{
float temperature = 0;
uint sensorId = 2;
var svc = new x86x64Lib.x86LibraryProxy();
temperature = svc.GetTemperature(sensorId);
Console.WriteLine($"temperature of {sensorId} is {temperature}, press any key to exit...");
This all works if I build all projects either as x86 or x64. The result for the temperature I get is 20. But, the whole idea was to use 32bit x86x64Lib.dll. That means that dotnetclient should be built as x64 and x86Library and x86x64 as x86, right? If I do this I get -1 as a result.
Should I build x86Library and x86x64 as x86 and dotnetclient as x64? If I do, so what can be the problem that I get -1?
CLARIFICATION
It seems that the provided example only works when both client and server are build in 32 or 64 bit. But not when the client build in 64bit and the server in 32bit. Can someone take a look please?
IMHO, the easiest way to do this is to use COM+ (Component Services) which is part of Windows for like 20 years or so (previous versions used to be called MTS...). It provides the surrogate infrastructure for you with tools, UI, and everything you need.
But that means you'll have to use COM, so it's good to know a bit of COM for this.
First create an x86 COM DLL. I've used ATL for that. Created an ATL project, added an ATL simple object to it, added the method to the IDL and implementation.
.idl (note the [out, retval] attributes so the temperature is considered a return value for higher level languages including .NET):
import "oaidl.idl";
import "ocidl.idl";
[
object,
uuid(f9988875-6bf1-4f3f-9ad4-64fa220a5c42),
dual,
nonextensible,
pointer_default(unique)
]
interface IMyObject : IDispatch
{
HRESULT GetTemperature(ULONG sensorId, [out, retval] FLOAT* temperature);
};
[
uuid(2de2557f-9bc2-42ef-8c58-63ba77834d0f),
version(1.0),
]
library x86LibraryLib
{
importlib("stdole2.tlb");
[
uuid(b20dcea2-9b8f-426d-8d96-760276fbaca9)
]
coclass MyObject
{
[default] interface IMyObject;
};
};
import "shobjidl.idl";
Method implementation for testing purposes:
STDMETHODIMP GetTemperature(ULONG sensorId, FLOAT* temperature)
{
*temperature = sizeof(void*); // should be 4 in x86 :-)
return S_OK;
}
Now, you must register this component in the 32-bit registry (in fact, if you're running Visual Studio w/o admin rights, it will complain at compile time that the component cannot be registered, that's expected), so on a 64-bit OS, you must run something like this (note SysWow64) with admin rights:
c:\Windows\SysWOW64\regsvr32 x86Library.dll
Once you've done that, run "Component Services", browse "Computers/My Computer/COM+ Applications", right click and create a New Application. Choose a name and a "Server application". It means your component will be hosted in COM+ surrogate process.
Once you've done that, browse "Components", right click and create a New Component. Make sure you select "32-bit registry". You should see your object's ProgId. In my case when I created my ATL project I added "MyObject" as a Progid, but otherwise it could be named something like "x86Library.MyObject" or "x86LibraryLib.MyObject"... If it's not there, than you made some mistake earlier.
That's it. Now, this .NET program will always be able to run, compiled as AnyCpu or x86 or x64:
class Program
{
static void Main(string[] args)
{
var type = Type.GetTypeFromProgID("MyObject"); // the same progid
dynamic o = Activator.CreateInstance(type);
Console.WriteLine(o.GetTemperature(1234)); // always displays 4
}
}
You can use Component Services UI to configure your surrogate (activation, shutdown, etc.). It also has an API so you can create COM+ apps programmatically.
You are not going to be able to directly call 32-bit code from 64-bit code (or the other way around), it simply is not going to happen.
There are alternatives, such as creating a 32-bit COM host program that then forwards calls to the DLL. Coupled with that you use DCOM standard marshalling so your 64-bit process can connect to the 32-bit host.
But if recompiling the 32-bit DLL is at all an option that is almost certainly your best option.
I've been using Unity 5 for a year and everything worked fine until last week when we had the idea to update our IDE to 5.3.1 version.
Now the compiler shows two errors:
The name `Dictionary' does not exist in the current context.
The name `Items' does not exist in the current context.
both localized in a simple KeyedCollection
public class CommandProcessQueueCollection : KeyedCollection<int, CommandProcessQueue>
{
public bool TryGetQueue(int id, out CommandProcessQueue queue)
{
if (Dictionary != null)
{
return Dictionary.TryGetValue(id, out queue);
}
foreach (var i in Items)
{
var k = GetKeyForItem(i);
if (Comparer.Equals(id, k))
{
queue = i;
return true;
}
}
queue = default(CommandProcessQueue);
return false;
}
protected override int GetKeyForItem(CommandProcessQueue queue)
{
return queue.Id;
}
}
After several attempts things became even more tricky as the exact same code has been compiled in 5 different machines with 5.3.1 installed.
Well, 2 out of 5 proved to compile without any error.
Furthermore, msbuild seems to compile the code without any error as well.
Probably, there are differences, among the machines, in the .NetFramework used by Mono for compilations.
Do you have any idea about this odd issue?
PS: I'm adding using System.Collections.ObjectModel and my current API compatibility option in Unity editor is set to .NET 2.0.
Ok, my team solved.
In those machines Windows Support for Editor 5.3.1f1 was not installed therefore the standard module of webplayer was running and few API of .NET were not available.
I'm creating a program that uses the CodeProject CoreAudioApi (pretty popular framework for manipulating audio), but the problem is the CoreAudioApi uses system calls that aren't available in any versions of Windows earlier than Vista. If I run a program with CoreAudioApi compiled with it (using a using statement as normal), the program will crash on anything earlier than Vista.
I've created this function to get the version number of the current environment:
win_version = Environment.OSVersion.Version.Major;
That returns the major version number I need. '6' is Vista/7, anything else is not, which is all I need to determine. Utilizing this, I need to determine whether or not to include the CoreAudioApi namespace if the OS is over or equal to '6'. From research, usings need to be compiled with the program, but I've also read about something called Reflection - which might be what I need.
Once I get the CoreAudioApi namespace using'd (sorry for the lack of terminology), the rest is easy. How can I do this?
TL;DR
I need some form of code that would effectively do this:
using System;
using System.Text;
//etc
if(currentWindowsVersion>=6) using CoreAudioApi;
Except control structures won't work outside of a class, and all namespaces are compiled with the program, not controlled individually.
Thanks!
EDIT: So far, I'm using this to load the CoreAudioApi namespace as a compiled assembly:
if(win_version>=6){
CoreAudioApi = Assembly.LoadFrom("CoreAudio.dll");
CoreAudioApi.GetLoadedModules();
CoreAudioApi.GetTypes();
MessageBox.Show("Loaded CoreAudioApi");
}
From here, what I need to do is actually use the types, and methods from the API. My code that works on Windows Vista/7 is this:
public static MMDeviceEnumerator devEnum;
public static MMDevice defaultDevice;
//later in a mute method:
defaultDevice.AudioEndpointVolume.Mute = true/false;
I don't even really need devEnum AFAIK, so really the only important lines are the last two (besides the comment).
I've just tried the following:
Create a new console application project
Add the CoreAudioApi project from CodeProject to the solution
Add a project reference to CoreAudioApi in my console app
Create the following classes:
interface IAudio { void SetVolume(float level); }
class XpAudio : IAudio {
public void SetVolume(float level) {
// I do nothing, but this is where your old-style code would go
}
}
class VistaAudio : IAudio {
public void SetVolume(float level) {
MMDeviceEnumerator devEnum = new MMDeviceEnumerator();
MMDevice defaultDevice = devEnum
.GetDefaultAudioEndpoint(EDataFlow.eRender, ERole.eMultimedia);
defaultDevice.AudioEndpointVolume.MasterVolumeLevel = level;
}
}
class Program {
static void Main(string[] args) {
IAudio setter = Environment.OSVersion.Version.Major >= 6
? (IAudio)new VistaAudio()
: (IAudio)new XpAudio();
float val = float.Parse(Console.ReadLine());
setter.SetVolume(val);
Console.ReadLine();
}
}
This runs on both my server (~ Windows 7) and local (Windows XP) machines. On my XP machine it'll happily take in a value and ignore it; on my server, it throws an exception, (presumably because I don't have a sound output). If I make my XP machine run the CoreAudioApi, I get an exception when I input a value, not before.
The question is, what are you doing differently to make your application break? Are you using CoreAudioApi code at startup?
EDIT: After seeing your edit, if you do this, you shouldn't need to mess about with Assembly.LoadFrom at all. The framework should dynamically load that assembly if (and only if) and when it needs to.
COREAUDIOAPI.dll does not work on XP or earlier, because they cant handle MMDEVICE API (Device Enumeration). I dont know about Vista.
I am building a webcam app based on the VideoRendererElement project (http://videorendererelement.codeplex.com/), which uses the DirectShowLib and Interop with an unmanaged activex component. I am using Visual Studio 2010, but am targeting .NET 3.5 (2.0 clr runtime).
I have been able to build and run the app on my development machine with no problem (outside of Visual Studio, even). However, when I deployed the app on the target machine (Windows 7,.NET up to date, C++ redistributable up to date) the app crashes. I set up an additional method to log the running application to a text file on the target machine a traced down one key difference, the unmanaged code calls the method in the managed code, only the static fields defined previously are missing. This only happens on the target machine (the one I deployed the code to). Here are some code snippets and what I logged. What is confusing is that this error ONLY occurs on the target machine. Any help pointing me in the right direction would be greatly appreciated.
namespace MediaBridge
{
.....
public class MediaBridgeManager
{
public delegate void NewMediaGraphInfo(MediaBridgeGraphInfo GraphInfo);
private static readonly Dictionary<string, NewMediaGraphInfo> _delegateHash = new Dictionary<string, NewMediaGraphInfo>();
......
public static void AddMediaGraphInfo(MediaBridgeGraphInfo GraphInfo)
{
if (_delegateHash.ContainsKey(GraphInfo.MediaUrl))
{
NewMediaGraphInfo callback = _delegateHash[GraphInfo.MediaUrl];
_delegateHash.Remove(GraphInfo.MediaUrl);
/* Suppress all errors on the callback */
try
{
callback(GraphInfo);
}
catch {}
}
}
......
public static bool RegisterCallback(string MediaUrl, NewMediaGraphInfo Callback)
{
bool returnval = true;
MediaUrl = FormatUrl(MediaUrl);
if (!_delegateHash.ContainsKey(MediaUrl))
{
_delegateHash.Add(MediaUrl, Callback);
}
else
{
returnval = false;
}
return returnval;
}
}
}
Before the .NET part of the app calls RegisterCallback() first and populates _delegateHash with a URL and callback function. This was verified in the logfile on the target machine.
Now the unmanaged part:
STDMETHODIMP CMediaBridgeSourceFilter::Load(LPCOLESTR lpwszFileName, const AM_MEDIA_TYPE *pmt)
{
/* Thread-saftey */
CAutoLock cAutoLockShared(&m_cSharedState);
HRESULT phr = S_OK;
/* Create the output pin for our filter */
m_pPin = new CMediaBridgeSourceFilterPin(&phr, this);
/* Create a new class to store information about us/graph in it */
MediaBridge::MediaBridgeGraphInfo ^ graphInfo = gcnew MediaBridge::MediaBridgeGraphInfo();
/* Set the media url sent */
graphInfo->MediaUrl = gcnew System::String(lpwszFileName);
/* Set the pointer to the filter graph */
graphInfo->FilterGraph = System::IntPtr(this->GetFilterGraph());
/* Store the pointer for our instance of the filter */
graphInfo->SourceFilter = System::IntPtr(this);
/* Do the callback into our managed code */
MediaBridge::MediaBridgeManager::AddMediaGraphInfo(graphInfo);
return phr;
}
According to my log file MediaBridge::MediaBridgeManager::AddMediaGraphInfo() is being called on the .NET side but the call back is never reached because the _delegateHash variable is now empty.
Here is what my log file says on the target machine that I'm trying to deploy the app on:
RegisterCallback(): MediaUrl = dshowmediabridge://d0ffd222-d023-483b-8fc7-4b4035ce3922/ Contains Key: True Delegate Hash count: 1
InitializeDirectShow(): RegisterCallback == true, Url == DShowMediaBridge://d0ffd222-d023-483b-8fc7-4b4035ce3922
AddMediaGraphInfo(): MediaUrl = dshowmediabridge://d0ffd222-d023-483b-8fc7-4b4035ce3922/ FilterGraph: 71122304 Contains Key: False Delegate Hash count: 0
Note how the Delegate Hash count (_delegateHash.Count) is now at 0 when the unmanaged code calls AddMediaGraphInfo().
Is there something I should be doing to identify the dll to COM/C++ on the target machine that VS is doing for me on my development machine?
How are you deploying and running the application on the target machine. Are you simply copying over the executable or are you creating an installer? If you are creating an installer, are you registering the AX file with RegSvr32?
The issue with COM components is they have to be registered in the registry on the box in question. On your box, you already have this registered, so you will not have an issue. On the target box, however, it may or may not be registered, at the whim of the user. If you have set up an installer, you have to "install" the AX file so it is registered in the registry. If not, the AX file cannot be found, no matter how you deploy the AX file. It is one of the downsides to COM.