Undefined behaviour while calling a function from dll - c

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.

Related

Runtime error when casting from FARPROC to function pointer with varargs

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.

getch undefined while compiling for the second time

I am using visual studio 2017 .
First I wrote the following code :
void main()
{
printf("abcdefgh %d hjhjh %d", 5, 6);
getch();
}
It ran perfectly fine .
But after that I modified the code to the following :
void main()
{
char abc[100];
strcpy_S(abc, "premraj");
printf("%s", abc);
printf("abcdefgh %d hjhjh %d", 5, 6);
getch();
}
But now I am getting an error with getch stating that "'getch' undefined, assuming extern returning int"
But this new code has been built on the existing code which recognized getch perfectly , how can it not recognize getch the second time ?
I checked out the following question :
getch() is working without conio.h - how is that possible?
which also carried a similar problem but here with modifications only I got this error .
There is an informative answer there by user named "Fatal Error" but still I would like to know about this intriguing phenomenon that is coming in after modifications . What can be the reason behind this ?
P.S : The following was my header file declarations for the first time :
#include <stdio.h>
and the following for the second time :
#include <stdio.h>
#include <string.h>
Once upon a time, if you called a function which the compiler had never heard of, like this:
#include <stdio.h>
int main()
{
int x = foo();
printf("%d\n", foo);
}
Anyway, if you did that, the compiler quietly assumed that foo() was a function returning int. That is, the compiler behaved just as if you had typed
extern int foo();
somewhere before you called foo.
But in, I think, C99, the language was changed. It was no longer legal to call a function you had not explicitly declared. Because there was lots and lots of code out there that was written under the previous set of rules, most compilers did not immediately begin rejecting the old-style code. Some continued to quietly assume that unrecognized functions returned int. Others -- like yours -- began noisily assuming that unrecognized functions returned int, emitting warnings along the lines of "'foo' undefined, assuming extern returning int".
It sounds like your question is that some time ago, your code containing calls to getch() was accepted without warning, but today, you're getting the warning "'getch' undefined, assuming extern returning int". What changed?
One possibility is that your code changed slightly. If your code used to contain the line
#include <conio.h>
somewhere, that file would have contained a declaration along the lines of
extern int getch();
and this would have goven the compiler the declaration that it needed, and you would not have gotten the warning. But if today your code does not contain that #include line, that explain why the warning started cropping up.
It's also possible that your compiler has changed somehow. It's possible you're using a new version of the compiler, that's more fussy, that has gone from quietly assuming, to normally assuming. Or, it's possible that your compiler options have changed. Many compilers can be configured to accept different variants of the language, corresponding to the different versions of the language standards that have been released over the years. For example, if some time ago your compiler was compiling for language standard "C89", but today, it's doing "C99" or "C11", that would explain why it's now being noisy with this warning.
The change in the compiler could be a change in the defaults as configured by a system administrator, or a change in the way you're invoking the compiler, or a change in your project's Makefile, or a change in the language settings in your IDE, or something like that.
A few more points:
getch is not a Standard C function; it's specific to Windows. Your program would be more portable, in general, if you didn't use it. Are you sure you need it? (I know what it's for; what I don't know if there's some other way of keeping your program's output window on the screen after if exits.)
You should get in the habit of declaring main() as int, not void. (void will work well enough, but it's not correct, and if nothing else, you'll get lots of negative comments about it.)
I think there's something wrong with your call to strcpy_S, too,

Unable to see global variable in certain C file, value seems to reset

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.

Minix - System call not correctly calling function?

I need to create a system call in Minix for a homework assignment. I've gotten most of the set up finished, but for some reason the function that the system call is actually calling isn't being found correctly. (Pardon any bad wording choices, I'm not sure the best words to explain this).
I've created a mylib.h in /usr/include (and /usr/src/include), with the following code:
#include <lib.h>
#include <unistd.h>
#include <stdio.h>
int mycall(){
message m;
return (_syscall(PM_PROC_NR, MYCALL, &m));
}
I also added mylib.h to the appropriate Makefile.
I've defined MYCALL in /usr/src/include/minix/callnr.h, and I've added do_mycall to the corresponding slot in /usr/src/servers/pm/table.h.
I've added int do_mycall(void); to /usr/src/servers/pm/proto.h, and I added a simple function declaration in misc.c.
int do_mycall(void){
printf("I've been called");
return 0;
}
I've also tried placing it in it's own .c file, which I added to the Makefile in that directory.
I performed make in /usr/src/servers/pm/ and /usr/src/include, and make includes in /usr/src/releasetools.
However, when I call mycall(), and catch the return value, it's -1.
I've added some prints, and I can tell that the function in mylib.h is being called, and MYCALL is correctly defined as the index in table.h, and table.h should have the do_mycall line correctly in place (though I don't really know how to test that it's there upon execution). So, all I can tell is that in _syscall, do_mycall isn't correctly mapping to it's function.
I tried replacing the prototype in photo.h with just the code in misc.c (so the prototype would be missing), but nothing happened differently, and make didn't complain.
Can anyone help me figure out what's causing this, or how I can narrow down where the disconnect is here?
If anyone knows where _syscall is defined, that might help, since I could maybe add some prints in it to figure out how far it's getting.
I was unable to find a specific cause, but after exhausting all options I could find, the issue appears to have been with my virtual machine. I repeated everything I did to set up the system call on VMware Player, instead of VirtualBox, and everything worked fine.

In C, main need not be a function?

This code compiles, but no surprises, it fails while linking (no main found):
Listing 1:
void main();
Link error: \mingw\lib\libmingw32.a(main.o):main.c:(.text+0x106) undefined reference to _WinMain#16'
But, the code below compiles and links fine, with a warning:
Listing 2:
void (*main)();
warning: 'main' is usually a function
Questions:
In listing 1, linker should have
complained for missing "main". Why
is it looking for _WinMain#16?
The executable generated from
listing 2 simply crashes. What is
the reason?
Thanks for your time.
True, main doesn't need to be a function. This has been exploited in some obfuscated programs that contain binary program code in an array called main.
The return type of main() must be int (not void). If the linker is looking for WinMain, it thinks that you have a GUI application.
In most C compilation systems, there is no type information associated with symbols that are linked. You could declare main as e.g.:
char main[10];
and the linker would be perfectly happy. As you noted, the program would probably crash, uless you cleverly initialized the contents of the array.
Your first example doesn't define main, it just declares it, hence the linker error.
The second example defines main, but incorrectly.
Case 1. is Windows-specific - the compiler probably generates _WinMain symbol when main is properly defined.
Case 2. - you have a pointer, but as static variable it's initialized to zero, thus the crash.
On Windows platforms the program's main unit is WinMain if you don't set the program up as a console app. The "#16" means it is expecting 16 bytes of parameters. So the linker would be quite happy with you as long as you give it a function named WinMain with 16 bytes of parameters.
If you wanted a console app, this is your indication that you messed something up.
You declared a pointer-to-function named main, and the linker warned you that this wouldn't work.
The _WinMain message has to do with how Windows programs work. Below the level of the C runtime, a Windows executable has a WinMain.
Try redefining it as int main(int argc, char *argv[])
What you have is a linker error. The linker expects to find a function with that "signature" - not void with no parameters
See http://publications.gbdirect.co.uk/c_book/chapter10/arguments_to_main.html etc
In listing 1, you are saying "There's a main() defined elsewhere in my code --- I promise!". Which is why it compiles. But you are lying there, which is why the link fails. The reason you get the missing WinMain16 error, is because the standard libraries (for Microsoft compiler) contain a definition for main(), which calls WinMain(). In a Win32 program, you'd define WinMain() and the linker would use the library version of main() to call WinMain().
In Listing 2, you have a symbol called main defined, so both the compiler & the linker are happy, but the startup code will try to call the function that's at location "main", and discover that there's really not a function there, and crash.
1.) An (compiler/platform) dependent function is called before code in main is executed and hence your behavior(_init in case of linux/glibc).
2) The code crash in 2nd case is justified as the system is unable to access the contents of the symbol main as a function which actually is a function pointer pointing to arbitrary location.

Resources