I have a simple project running under Windows. It consists of two DLLs and one EXE.
The EXE loads the two DLLs. Each will create a shared memory object in a class instatiated by a std::unique_ptr globaly. The crash happens during FreeLibrary and only if I use the /MTd switch (Multi-threaded Debug) instead of /MDd (Multi-threaded Debug DLL).
I built boost libs using:
b2.exe -a -j %NUMBER_OF_PROCESSORS% --prefix=%BOOST% --libdir=%BOOST%/lib/x86 --reconfigure --build-type=complete --toolset=msvc-14.2 link=static address-model=32 runtime-link=static runtime-link=shared threading=multi define=BOOST_USE_WINDOWS_H define=NOMINMAX install
where %BOOST% points to my BOOST installation folder.
I hope someone can help me,
Christian.
The example code:
APOLLOSHM\dllmain.cpp
#include <memory>
#include "../shared/SHMBASE.h"
std::unique_ptr<SHM> shm;
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call, LPVOID )
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
shm = std::make_unique<SHM>("a_shm");
break;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
PHONYXSHM\dllmain.cpp
#include <memory>
#include "../shared/SHMBASE.h"
std::unique_ptr<SHM> shm;
BOOL APIENTRY DllMain( HMODULE hModule, DWORD ul_reason_for_call, LPVOID )
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
shm = std::make_unique<SHM>("p_shm");
break;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
shared\SHMBASE.h
#ifndef SHAREDMEM_H
#define SHAREDMEM_H
#include <boost/interprocess/shared_memory_object.hpp>
#include <boost/interprocess/mapped_region.hpp>
class SHMBASE
{
boost::interprocess::shared_memory_object shm;
boost::interprocess::mapped_region region;
protected:
void* addr{ nullptr };
public:
SHMBASE(const char* n)
{
try {
boost::interprocess::shared_memory_object::remove(n);
shm = boost::interprocess::shared_memory_object(
boost::interprocess::open_or_create,
n, boost::interprocess::read_write);
}
catch (boost::interprocess::interprocess_exception & ex) {
throw std::runtime_error(ex.what());
}
}
void create_shm(size_t size)
{
shm.truncate(size);
region = boost::interprocess::mapped_region(shm,
boost::interprocess::read_write);
addr = region.get_address();
}
};
struct shared_memory_info
{
char x[20];
int y;
};
class SHM : public SHMBASE
{
public:
SHM(const char* n) :
SHMBASE(n)
{
create_shm(sizeof(shared_memory_info));
shm = static_cast<shared_memory_info*>(addr);
}
shared_memory_info* shm;
};
#endif
SharedMemTest\SharedMemTest.cpp
#include <iostream>
#include <utility>
#include <vector>
#include <string>
#include <Windows.h>
struct LIBOBJ
{
HMODULE libhandle{ nullptr };
LIBOBJ(std::string libname){
libhandle = LoadLibraryA(libname.c_str());
if (!libhandle) {
throw std::runtime_error("Cannot open library");
}
}
~LIBOBJ() {
if (libhandle){
FreeLibrary(libhandle);
}
}
};
int main(){
std::vector<std::string> dlls = {"ApolloSHM.dll", "PhonyxSHM.dll"};
std::vector<std::unique_ptr<LIBOBJ> > objs;
try{
for (auto& n : dlls){
objs.emplace_back(std::make_unique<LIBOBJ>(n));
}
// if freelibrary in reverse order no crash
// for (auto it = objs.rbegin(); it != objs.rend(); ++it)
// if in order of loading it crashes, but only with /MTd
// for (auto it = objs.begin(); it != objs.end(); ++it)
for (auto it = objs.begin(); it != objs.end(); ++it){
it->reset();
}
}
catch (std::exception & e){
std::cout << "Exception: " << e.what() << std::endl;
}
return 0;
}
I think I solved the issue (maybe just for me). The problem isn't the /MTd switch of the compiler.
I think the problem is related to the singleton implementation inside boost::interprocess::shared_memory_object. My project structure is as follows:
An EXE file loads a DLL (a driver wrapper) which can load several device driver DLLs in parallel. Two of the driver DLLs are using their own shared_memory_object's as described in the doc and it work in both cases. Until I call FreeLibrary for the driver DLLs. In that case always the second FreeLibrary crashes (but not with /MDd I didn't understand this seconds fact, sorry).
I solved the issue by creating a boost::interprocess::shared_memory_object inside the driver wrapper DLL. I just instantiate such an object and in the next line I remove it. If I do this my DLLs does not crash any more.
I hope this helps the developer of boost::interprocess.
Kind regards,
Christian
Related
./index.cpp
#include <functional> // std::function
#include <iostream> // std::cout
#include <Windows.h>
#include "Keyboard_hook/index.h"
int main () {
HMODULE DLL_handle = LoadLibraryA("Keyboard_hook/index.dll");
std::function<Hook_interface *()> get_hook = reinterpret_cast<Hook_interface *(*)()>(GetProcAddress(DLL_handle, "get_hook"));
Hook_interface *hook = get_hook();
hook->start_hooking();
system("pause");
hook->stop_hooking();
FreeLibrary(DLL_handle);
return 0;
}
./Keyboard_hook/index.dll
#include <iostream> // std::cout
#include <Windows.h>
#include "index.h"
LRESULT CALLBACK KeyboardProc (int n_code, WPARAM w_param, LPARAM l_param);
namespace global {
HINSTANCE instance_handle;
}
class Hook : public Hook_interface {
private:
static HHOOK hook_handle;
public:
static HHOOK get_hook_handle () {
return Hook::hook_handle;
}
void start_hooking () {
MSG msg;
Hook::hook_handle = SetWindowsHookExA(WH_KEYBOARD, KeyboardProc, global::instance_handle, 0);
while(GetMessage(&msg, NULL, 0, 0) > 0) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
void stop_hooking () {
if (Hook::hook_handle != nullptr) {
UnhookWindowsHookEx(this->hook_handle);
Hook::hook_handle = nullptr;
}
}
};
HHOOK Hook::hook_handle = nullptr;
BOOL WINAPI DllMain ([[maybe_unused]] HINSTANCE instance_handle, [[maybe_unused]] DWORD call_reason, [[maybe_unused]] LPVOID reserved) {
switch (call_reason) {
case DLL_PROCESS_ATTACH:
global::instance_handle = instance_handle;
break;
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
break;
case DLL_PROCESS_DETACH:
break;
}
return true;
}
LRESULT CALLBACK KeyboardProc ([[maybe_unused]] int n_code, [[maybe_unused]] WPARAM w_param, [[maybe_unused]] LPARAM l_param) {
std::cout << "KeyboardProc()" << "\n";
return CallNextHookEx(Hook::get_hook_handle(), n_code, w_param, l_param);
}
extern "C" _declspec(dllexport) Hook_interface *get_hook () {
return new Hook();
}
./Keyboard_hook/index.h
#include <Windows.h> // HHOOK
class Hook_interface {
public:
virtual void start_hooking () = 0;
virtual void stop_hooking () = 0;
virtual ~Hook_interface () = default;
};
I built those files like that.
cl index.cpp /EHsc /source-charset:utf-8 /std:c++17 /W4 /WX /link /MACHINE:X64 /OUT:a.exe
cl Keyboard_hook/index.cpp user32.lib /EHsc /LD /source-charset:utf-8 /std:c++17 /W4 /WX /link /MACHINE:X64
And I executed a a.exe, but it only print KeyboardProc() messages for 32-bit applications.
but DLL was well injected into 64-bit applications. (I figured out using Process Explorer)
I know that 64-bit DLL doesn't inject to 32-bit applications, So I create a message loop for that.
I'm curious why hook doesn't work for 64-bit applications. When I type keys on 64-bit applications, there's no output. I don't know what I did something wrong. Thanks for reading ! :D
I'm trying to run a program for an internal video game cheat, and yet when I try to run it I get 231 errors from cmath, almost all of which saying "the global scope has no x" where x is a function.
I'm not even using #include cmath, which makes this stranger.
My code:
#include "stdafx.h"
#include <Windows.h>
#include <iostream>
struct gameOffsets
{
DWORD lplayer = 0xC5e87C;
DWORD fJump = 0x50DE048;
DWORD flags = 0x100;
}offsets;
struct values
{
DWORD localPlayer;
DWORD gameModule;
BYTE flag;
}val;
void main()
{
AllocConsole();
freopen("CONOUT$", "w", stdout);
val.gameModule = (DWORD)GetModuleHandle("client_panorama.dll");
val.localPlayer = *(DWORD*)(val.gameModule + offsets.lplayer);
if (val.localPlayer == NULL)
while (val.localPlayer == NULL)
val.localPlayer = *(DWORD*)(val.gameModule + offsets.lplayer);
std::cout << std::hex << val.localPlayer << std::endl;
while (true)
{
val.flag = *(BYTE*)(val.gameModule + offsets.flags);
if (GetAsyncKeyState(VK_SPACE) && val.flag & (1 << 0))
*(DWORD*)(val.gameModule + offsets.fJump) = 6;
}
}
BOOL APIENTRY DllMain(HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
{
DisableThreadLibraryCalls(hModule);
CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)main, NULL, NULL,
NULL);
}
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
Any help would be appreciated.
Cheers.
There are no compiler time errors with this code, it compiles without issue. Your problem does not exist in the code you posted.
Start a new project and just paste your code in, that should solve the issue. If it does not, reinstall Visual Studio.
I'm trying to build a windows dll using mingw-64 that once loaded starts printing "Hello World" indefinetly.
Here's my dll.c
#include <stdio.h>
#include <windows.h>
#include "dll.h"
#include "main.h"
HINSTANCE hThisModule;
DWORD mainThread() {
while(1) {
printf("Hello world!");
}
}
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) {
static HANDLE hThread;
hThisModule = hinstDLL;
switch (fdwReason)
{
case DLL_PROCESS_ATTACH:
hThread = CreateThread(0, 0, mainThread, 0, 0, 0);
break;
case DLL_PROCESS_DETACH:
break;
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
break;
}
return TRUE;
}
void dummy() {
Hello();
}
and here's my dll.h:
#ifndef DLL_H_
#define DLL_H_
#ifdef BUILD_DLL
/* DLL export */
#define EXPORT __declspec(dllexport)
#else
/* EXE import */
#define EXPORT __declspec(dllimport)
#endif
#endif /* DLL_H_ */
so I've built a simple program that loads my DLL to see if it's working correctly, here it is: hello.cpp
#include <windows.h>
#include <iostream>
typedef int (__stdcall *f_funci)();
int main()
{
HINSTANCE hGetProcIDDLL = LoadLibrary("./wow.dll");
if (!hGetProcIDDLL) {
std::cout << "could not load the dynamic library" << std::endl;
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
Now, when I compile hello.cpp into hello.exe and dll.c into wow.dll, I get nothing on my console. What's wrong?
As has been already mentioned, your mainThread function has wrong signature. Try something like this:
DWORD WINAPI mainThread(LPVOID lpParam)
{
UNREFERENCED_PARAMETER(lpParam);
while (1)
{
printf("Hello world!\n");
Sleep(1000);
}
return 0;
}
This works just fine for me. I modified your .exe so that you could drag and drop .dll onto it to test:
#include <windows.h>
#include <iostream>
int main(int argc, char *argv[])
{
if (argc < 2)
{
std::cout << "drag drop dll over exe" << std::endl;
std::cin.get();
return EXIT_FAILURE;
}
HINSTANCE hGetProcIDDLL = LoadLibraryA(argv[1]);
if (!hGetProcIDDLL)
{
std::cout << "could not load the dynamic library" << std::endl;
std::cin.get();
return EXIT_FAILURE;
}
std::cin.get();
return EXIT_SUCCESS;
}
First, I'd like to mention that it is not advisable to implement such a busy loop in your thread.
As for the issue you are experiencing, there are several potential issues here:
printf is a CRT function, however you are calling CreateThread() instead of beginthread(ex), so the CRT is not initialized properly.
Dll entry point is a notoriously problematic place. You can hardly call any kernel32 function from there, let alone CRT ones (see DllMain entry point and Dynamic Link Library Best Practices).
In most cases, it is advisable to implement separate Init and Exit functions that the client will need to call when using your library.
I'm building a password filter as demonstrated with by the following link: http://msdn.microsoft.com/en-us/library/windows/desktop/ms721882(v=vs.85).aspx
I attempted to build a dll and load it on a test machine following the instructions provided by MS and discovered something was obviously wrong as the dll was not getting loaded. So I then decided to run a unit test program on the dll and that doesn't seem to work either. Rather, it works if I use mangled functions without use of the extern "C" directive or an .def file. As soon as I do use extern "C" or the def file, the code doesn't work.
The Code below produces the error code 127: The specified procedure could not be found. Despite me using extern "C" and using Dependency Walker to get the name of the function, I'm told by the code that the function could not be found.
Here is the unit test app:
#include "stdafx.h"
#include <Windows.h>
#include <NTSecAPI.h>
#include <strsafe.h>
typedef NTSTATUS (__stdcall *MYPROC)(PUNICODE_STRING, ULONG, PUNICODE_STRING);
int _tmain(int argc, _TCHAR* argv[])
{
MYPROC ProcAdd;
HMODULE MyDllHnd = LoadLibrary(TEXT("C:\\Users\\mmatovic\\Documents\\Visual Studio 2012\\Projects\\PasswordFilterUnitTest\\Debug\\PasswordFilter.dll"));
if (NULL == MyDllHnd)
{
DWORD dwError = GetLastError();
cout << "Error: " << dwError << endl;
}
ProcAdd = (MYPROC)GetProcAddress(
MyDllHnd,
"PasswordChangeNotify");
ULONG rid = 0;
if (NULL != ProcAdd)
{
(ProcAdd)((PUNICODE_STRING)"test",(ULONG)0,(PUNICODE_STRING)"test");
} else {
DWORD dwProcError = GetLastError();
cout << "Error: " << dwProcError << endl;
}
return 0;
}
Here is the code for the actual DLL:
#include "stdafx.h"
#define LOGFILE "c:\\PasswordFilter.txt"
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
void WriteToLog (PUNICODE_STRING str)
{
#ifdef LOGFILE
FILE* log = fopen(LOGFILE, "a");
if(NULL == log)
{
return;
}
fprintf(log, "%s\r\n", str);
fclose(log);
#endif
return;
}
BOOLEAN __stdcall InitializeChangeNotify(void)
{
return TRUE;
}
NTSTATUS __stdcall PasswordChangeNotify(
PUNICODE_STRING UserName,
ULONG RelativeId,
PUNICODE_STRING NewPassword
)
{
WriteToLog(UserName);
WriteToLog(NewPassword);
return 0;
}
BOOLEAN __stdcall PasswordFilter(
PUNICODE_STRING AccountName,
PUNICODE_STRING FullName,
PUNICODE_STRING Password,
BOOLEAN SetOperation
)
{
return TRUE;
}
And lastly the contents of the .def file
LIBRARY PasswordFilter
EXPORTS
InitializeChangeNotify
PasswordChangeNotify
PasswordFilter
Also the stdafx.h file generated in VS for the DLL code:
#pragma once
#include "targetver.h"
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
// Windows Header Files:
#include <stdio.h>
#include <windows.h>
#include <winnt.h>
#include <NTSecAPI.h>
I am trying to make a program to store the value 500 into the calculator's memory address for the MR (Memory Restore) button on the calculator application.
I know that the address for this integer is
"calc.exe"+00073320 + 0 + C
If I use a program like cheat engine, I can get the current address for the instance of the calculator.exe i'm running, and write to it just fine that way. However, since this is not a static address, I need a way to get the module base address.
I tried using this GetModuleBase function (see code below) to get the Base Address of the calc.exe, but my issue is that I cannot get the base address. The function always returns 0 instead of the correct address.
I debugged it and found that in the GetModuleBase function, it is not even cycling once through the while loop because bModule is returning 0 from the Module32First function.
#include <tchar.h>
#include <windows.h>
#include <TlHelp32.h>
#include <iostream>
#include <Psapi.h>
#include <wchar.h>
#pragma comment( lib, "psapi" )
using namespace std;
DWORD GetModuleBase(LPSTR lpModuleName, DWORD dwProcessId)
{
MODULEENTRY32 lpModuleEntry = {0};
HANDLE hSnapShot = CreateToolhelp32Snapshot( TH32CS_SNAPMODULE, dwProcessId );
if(!hSnapShot)
return NULL;
lpModuleEntry.dwSize = sizeof(lpModuleEntry);
BOOL bModule = Module32First( hSnapShot, &lpModuleEntry );
while(bModule)
{
if(!strcmp( lpModuleEntry.szModule, lpModuleName ) )
{
CloseHandle( hSnapShot );
return (DWORD)lpModuleEntry.modBaseAddr;
}
bModule = Module32Next( hSnapShot, &lpModuleEntry );
}
CloseHandle( hSnapShot );
return NULL;
}
int main() {
HWND hWnd = FindWindow(0, "Calculator");
DWORD BaseAddr;
if(hWnd == 0){
MessageBox(0, "Error cannot find window.", "Error", MB_OK|MB_ICONERROR);
} else {
DWORD proccess_ID;
GetWindowThreadProcessId(hWnd, &proccess_ID);
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, proccess_ID);
if(!hProcess){
MessageBox(0, "Could not open the process!", "Error!", MB_OK|MB_ICONERROR);
} else {
int newdata = 500;
BaseAddr = GetModuleBase("calc.exe",proccess_ID);
//GetModuleBase is always returning 0, so I am not getting the correct base address
DWORD newdatasize = sizeof(newdata);
if(WriteProcessMemory(hProcess, (LPVOID)0x002413FC, &newdata, newdatasize, NULL)){
cout << "Memory successfully written." << endl;
} else {
cout << "Memory failed to write." << endl;
}
CloseHandle(hProcess);
}
}
return 0;
}
Summary: I cannot get the correct base address using my GetModuleBase function, and I need to figure out what I am doing wrong so that I can get the correct base address for the "calc.exe" process.
You should read the modules like this:
#include <windows.h>
#include <TlHelp32.h>
#include <iostream>
//You don't have to use this function if you don't want to..
int strcompare(const char* One, const char* Two, bool CaseSensitive)
{
#if defined _WIN32 || defined _WIN64
return CaseSensitive ? strcmp(One, Two) : _stricmp(One, Two);
#else
return CaseSensitive ? strcmp(One, Two) : strcasecmp(One, Two);
#endif
}
//You read module information like this..
MODULEENTRY32 GetModuleInfo(std::uint32_t ProcessID, const char* ModuleName)
{
void* hSnap = nullptr;
MODULEENTRY32 Mod32 = {0};
if ((hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, ProcessID)) == INVALID_HANDLE_VALUE)
return Mod32;
Mod32.dwSize = sizeof(MODULEENTRY32);
while (Module32Next(hSnap, &Mod32))
{
if (!strcompare(ModuleName, Mod32.szModule, false))
{
CloseHandle(hSnap);
return Mod32;
}
}
CloseHandle(hSnap);
return {0};
}
int main()
{
//Change the process ID below..
BYTE* BaseAddr = GetModuleInfo(5172, "calc.exe").modBaseAddr;
std::cout<<"BASE ADDRESS: "<<(void*)BaseAddr<<"\n";
return 0;
}
EDIT: After further investigation, I found that Visual Studio was compiling for an x32 platform but calc.exe is an x64 process..
To get Visual Studio to compile for x64 you need to do the following:
Then click and select "NEW" from the following drop-down menu:
Next in the following drop down, select x64:
Save the settings and rebuild the project and it should work..