I'm working on an old program that doesn't save or load its files anymore. While looking around in a DLL for a place to start, I noticed that there is some logging functionality that is disabled by default but should still work. Using a proxy DLL, I managed to activate logging by calling the right functions from the real DLL. However, I got stuck at using the actual logging functions, as the program crashes with Error 0xc0000142 whenever I get close to using them. All binaries involved are 32 bit.
Here's what I'm doing in my proxy DLL:
// undname ?ForceDebugLog##YAXXZ = void __cdecl ForceDebugLog(void)
typedef void (*FDLAddr_t)(void);
FDLAddr_t ForceDebugLog;
// undname ?LogInfo##YAXPBDZZ = void __cdecl LogInfo(char const *,...)
typedef void (*LIAddr_t)(char const *, ...);
LIAddr_t LogInfo;
// called on DLL_PROCESS_ATTACH
void setupFuncs() {
HMODULE trueDll= GetModuleHandleA(".\\realDll.dll");
ForceDebugLog = (FDLAddr_t)GetProcAddress(realDll, "?ForceDebugLog##YAXXZ");
// LogInfo = (LIAddr_t)GetProcAddress(realDll, "?LogInfo##YAXPBDZZ");
}
Now, I can just do ForceDebugLog() and logging gets enabled. However, as soon as I uncomment the LogInfo line, the program crashes on startup with Windows showing the error 0xc0000142.
Further experimentation shows that GetProcAddress returns the address of LogInfo in the DLL, i.e. this is working correctly. Also, everything works if LogInfo was a FARPROC. As soon as I add the cast to LIAddr_t, the error comes back.
How can I work around this issue? Do I need to take a different approach for functions with varargs? If this is a problem that has to be solved using C++ constructs, that's fine too.
I apologise for the waste of everyone's time.
While looking at my DLL in ghidra, I noticed that there were some strings defined that appeared nowhere in my code. As it turns out, some old object files from earlier experiments were accidentally linked into the DLL. One of the experiments was a reimplementation of LogInfo which caused the compiler/linker to produce an incorrect result without throwing an error or warning (unless /wd5045 suppresses it, which I highly doubt).
This has the side effect that I now have to rework my makefile. Oh joy.
Related
Though the title reads dll, the actual library loaded is an exe. Suppose I have an exe file testlib.exe. I need to call a function from it, let it be func(). What I am doing is:
#include <windows.h>
#include <stdio.h>
typedef char* (__stdcall *f_func)();
int main()
{
HINSTANCE hGetProcIDDLL = LoadLibrary("testlib.exe");
f_func func = (f_func)GetProcAddress(hGetProcIDDLL, "func");
printf(func());
return 0;
}
Now most of the times I run the program it gives the correct output, but in some cases (1 out of 8 for example) it gives either garbage text or values of some other variables in testlib.exe. I identify it's due to wrong memory reference but can neither explain nor solve it.
My os is windows and I'm using mingw gcc. I do not use MSVS as it does not fit well in code portability.
PS: The testlib.exe is well built and I cannot change it. It is unlikely to have any problem. I tried different versions and also it's running in other build systems well. Also it is a release build, so less hope in debugging.
UPDATE:
I've seen this question, it says that it is possible by patching the IAT table. My point is completly different. I am using a function that is neither initialised by main nor by dllmain.
Actually what I found that GetProcAddress gives right function pointer everytime. What gets messed is the return object. For example if the function in exe library is:
const char* func() {
return "Sometext";
}
then sometimes the reference to "sometext is sometimes wrong. I do suspect randomised loading but I'm not sure. I renamed the exe as dll but no change observed.
I try to port some functionality from newest stable kernel (4.6.3) to older one for whatever reason I've got for doing so. Everything went pretty good but I keep getting mm/filemap.c:1183:4: error: implicit declaration of function '__SetPageReferenced'
I cannot find oryginal definition of
static inline void __SetPageReferenced(struct page *page) which is funny considering that oryginal 4.6.3 compiles no problem despite fact I can't find that definition in it's sources
Forgot to mention, there are similar declarations in include/linux/page-flags.h I would just copy and paste it right here if I knew where to find it. Unfortunately I wasn't able to find any useful mention of it anywhere online.
So thanks to the conversation in comment section, especially to #LPs input I came up with sort of a hack where I define:
#define __SetPageReferenced(page) set_bit(PG_referenced, &(page)->flags) which get rid of the implicit declaration problem. I'll post whether it works or not when I finally port my functionality and base on the results might reopen or close the question.
Cheers!
Side note:
Found out that you can use extern void mark_page_accessed(struct page *); instead while fixing different problem.
Declare macro __SETPAGEFLAG here, use it for referenced bit here
Result:
static __always_inline void __SetPageReferenced(struct page *page) \
{ __set_bit(PG_referenced, &PF_HEAD(page, 1)->flags); }
I have a very frustrating bug that others on the team can't reproduce. I have tried cleaning the project, wiping the directory, pulling from the repository, rebuilding, and even testing in VS 2013.
Background: a.c, b.c, c.c and b.inc are all compiled into a DLL (assume they are externed). setfoo() is called first from managed code. So far so good.
Later on, testfoo() is called. The global variable is fine, there are no issues. Then testfoo2() is called. This is where things get interesting. I have the memory debugger on with foo's address, and it will read 4 in memory. However, if you hover over code in visual studio, it returns 0!. Also, it will output 0. There are many global variables (including FILE handles and they are reset to zero(causing nasty ASSERT failures), ONLY in c.c, but are fine when inspected with the debugger). There are many other x.c modules with that include that have no issues.
Ok, now testfoo() is called again. Everything is fine in b.c world. The scary part is that the issue happens on only on my workstation! Any clues on how to debug this?
This is from my memory, I believe the code is very close to this skeleton:
b.inc
int foo;
a.c
#include <b.inc>
void setfoo(){
foo = 4;
}
b.c
#include <b.inc>
void testfoo(){
printf(foo); //works
}
c.c
#include <b.inc>
void testfoo2(){
printf(foo); //foo is now 0
}
To Add: This is very complex, legacy code (think 70s), in a very large company and not much can be changed. There are thousands of variables that would be affected if we start adding extern. Also, I tried extern on one variable, and it still has an issue with that file.
I left out one tidbit. 'testfoo2()' launches in a managed thread. Again, this seems to be related to my machine, could be some setting in visual studio, dunno at this point, we want to just re-image the box.
You need to declare as extern:
extern int foo;
And then in one (and only one) of the source files you define it:
int foo;
That way there is only one symbol in one source file, and all other sources including the header know to link to it. If you omit extern then each source file thinks it has its own local, private copy of foo.
So which file should define it? The one that is most relevant. I would say a.c, since that provides functions to operate on foo. I would consider that file to be the 'owner'. However, it's a little confusing because you declare it in b.inc, suggesting that b.c is the owner.
try this.
b.inc
extern int foo;
a.c
#include <b.inc>
int foo;
void setfoo(){
foo = 4;
}
I posted this in another thread, but I'll duplicate the answer here. It is a pretty subtle bug that may save you a few hours:
Ok, here is what happened: (In case you run into this in the future)
1)On a prior build someone split all the C# Extern dll calls into two files.( I wasn't told)
2)They created a post build process to copy the dll (see where this is going) to another directory.
3)There was a user settings file involved which wasn't in the repo, but had a default in code.
4)One of the extern DLL functions kept my original default (in filea.cs), but the new default (fileb.cs) pointed to the post build location.
There is no real way to reflect the dll's path at runtime, as far as I know....
So, when I entered the function with the dll copy, OF COURSE there are no global variables, because it is a FRESH COPY of the dll. That is expected behavior.
The memory debugger was correct, because somewhere the other dll was in memory holding the correct variable.
How could I prevent this in the future? It seemed VS was duped when it loaded a copy of the same dll.
Help!
I am receiving this error when viewing the contents of an inbound function parameters in my Delphi 4 application.
The code calls a function in a dll with 3 parameters (app.handle, pchar, boolean)
The declaring function is in externs.pas and declared as:
function AdjustVoucherDifference(hOwner :HWnd; Receipt_ID :PChar;
bCommit: Boolean): boolean; stdcall;
external 'FBCoupon.dll' name 'AdjustVoucherDifference';
in another source file, the code calls it as:
AdjustVoucherDifference(Application.Handle, PChar(Receipt_ID), true);
When stepping through the code in debug mode, I can see valid values in the source file, but when it breaks on the line in externs.pas, the tooltip for the values (or CTRL+F7) shows that the symbols have been eliminated from the linker and I receive exceptions when the execution is in the dll.
The DLL is developed in CBuilder4 and the particular function is declared as:
BOOL __stdcall __DLLTYPE__ AdjustVoucherDifference(HWND hOwner,
char *receipt_id, bool commit);
Compiler optimization is turned off.
Thanks!!!
Set a breakpoint before the call to the external function (not a breakpoint on the external declaration).
Open the debugger disassembly window. (I forget the exact menu path to get there)
Step through the machine instructions one at a time. You don't need to understand all of them (though it doesn't hurt), but keep a sharp eye out for jump and call instructions.
There will be a bit of chatter as the code sets up the parameters for the call, then a call instruction.
Follow (step into) the call instruction. Since this is an external call, expect to see a jump indirect instruction.
Follow that jump to its destination. You should now be inside the C++ DLL. If you built the DLL in CBuilder with debug info, you should have symbol info and source line info as well.
If your parameter declarations on the Delphi side don't match the expectations on the C++ side, then you should start to see things going awry on the C++ side of the call, which could lead to an access violation exception or a runtime error generated by the C++ dll.
The linker isn't affected by compiler optimizations. The linker will "smartlink out" any routine that it can prove is will never be called in your program. Unfortunately, this means it's not available for the debugger to call into.
My solution to this, when it's happened to me in the past, is generally to put a meaningless call to the routine in question in an initialization section. The smartlinker won't mess with those. Can you do this without causing any errors?
initialization
AdjustVoucherDifference(0, '', true); //DO NOT SMARTLINK THIS OUT!
end;
Note that BOOL and Boolean are different. BOOL is defined in Windows.pas as
type
BOOL = LongBool;
so SizeOf(BOOL) = 4 while SizeOf(Boolean) = 1
Even if it would not help you with your problem, replace Boolean by BOOL (or LongBool) in Delphi declaration to make the declaration correct.
I'm trying to make a call to a DLL function (via GetProcAddress etc) from C, using lcc compiler. The function gets called and everything goes well, but it looks like the top of the stack gets corrupted. I've tried to play with calling conventions (__stdcall / __cdecl), but that didn't help.
Unfortunately I don't have access to the dll code, and have to use the lcc compiler.
I found that this simple hack avoids stack corruption:
void foo(params)
{
int dummy;
dll_foo(params);
}
Here dll_foo is the pointer returned by GetProcAddress, and the stack is kind of protected by the dummy variable. So it's not the stack pointer that gets corrupted, but the data at the top of the stack. It works like this, but I'd like to know the reason of the corruption.
Any ideas?
UPD:
As asked in the comments, here are the actual function types:
typedef unsigned char (CALLBACK Tfr)(unsigned char);
typedef void (CALLBACK Tfw)(unsigned char,unsigned char);
typedef int (CALLBACK Tfs)(int);
typedef void (CALLBACK Tfwf)(int*,int);
All they show a similar behavior.
Unfortunately, it is not so straightforward to attach a debugger, as the code is compiled and launched by Matlab, using the LCC compiler, and there is no debugging support. Probably I will have to reproduce this problem in a standalone configuration, but it is not that easy to make it.
Sounds like you use MSVC, Debug + Windows + Registers. Look at the value of ESP before and after the call. If it doesn't match then first change the calling convention in the function pointer declaration (did you do that right?) If it still doesn't match then it is __stdcall and you haven't guessed the arguments you need to pass correctly.
Or the function could just clobbers the stack frame, it isn't impossible.
Posting your function pointer declaration that shows the real arguments would probably help diagnose this better.
It sounds to me like you were on the right track with looking at the calling convention. The main thing you need to do is ensure that the caller and callee are both using the same convention. Typically for a DLL, you want to use __stdcall for both, but if (as you say) you have no control over the DLL, then you need to modify your code to match what it's doing. Unfortunately, it's almost impossible to guess what that is -- I'm pretty sure lcc (like most C and C++ compilers) can produce code to use a variety of conventions.
Based on your hack working by putting an extra dword on the stack, it sounds like you currently have a mismatch where both the caller and the callee are trying to clear arguments off the stack (e.g., the caller using __cdecl and the callee using __stdcall.
You could try to "follow" the call to dll_foo() i assembler using a debugger, at check out exactly what the routine does stack-wise.