Executable File IMAGE_OPTIONAL_HEADER ImageBase is 0 - c

I've encountered a problem I am trying to figure out for a while now but I am unable to find anything about it, I am trying to get a mapped file image base from its optional header found in the PE header but the value in the ImageBase is 0?
The file I am trying to get this value from is a 64 bit executable (PE64), so what I am doing is I open the file with (CreateFileW function), then I map it using (CreateFileMappingW and MapViewOfFile functions), then I get the PE Header file with these functions:
IMAGE_DOS_HEADER* FileUtils_GetFileDOSHeader (void* Arg_FileViewMap) {
if (Arg_FileViewMap != NULL) {
return (IMAGE_DOS_HEADER*) Arg_FileViewMap;
}
return NULL;
}
IMAGE_NT_HEADERS* FileUtils_GetFilePEHeader (void* Arg_FileViewMap) {
if (Arg_FileViewMap != NULL) {
IMAGE_DOS_HEADER* Func_FileDOSHeader = FileUtils_GetFileDOSHeader(Arg_FileViewMap);
if (Func_FileDOSHeader != NULL) {
return (IMAGE_NT_HEADERS*) ((INT64) Func_FileDOSHeader + Func_FileDOSHeader->e_lfanew);
}
}
return NULL;
}
Then I use this function to get the optional header or do it directly, same result:
IMAGE_OPTIONAL_HEADER* FileUtils_GetFileOptionalHeader (void* Arg_FileViewMap) {
if (Arg_FileViewMap != NULL) {
IMAGE_NT_HEADERS* Arg_FilePEHeader = FileUtils_GetFilePEHeader(Arg_FileViewMap);
if (Arg_FilePEHeader != NULL) {
return (IMAGE_OPTIONAL_HEADER*) &Arg_FilePEHeader->OptionalHeader;
}
}
return NULL;
}
Then I try to get value and print it out so I would know that its not 0 like so:
wprintf(L"File image base: 0x%015X\n", FileUtils_GetFileOptionalHeader(Func_TargetFileViewMap)->ImageBase);
That is all! Once I compile this code for 64bit and run it, it prints out 0 but it should give me 0x00000010000000, so what is wrong here? The value does print out correctly, I made sure that the value is indeed 0 a lot of times.
Now things to note:
Some executables do give me the ImageBase value, but most of them give me 0 even though that is wrong, for example I open notepad and that gives me 0 but the value should be 0x00000010000000, and to show you that here is a screenshot of what CFF Explorer sees: (http://prntscr.com/) <- Click
It appears that all other values are correct except the ImageBase that is 0 for some reason, if I print out the EntryPoint then the value does match with what the CFF Explorer tells me.
I am using GCC (From MinGW-w64) compiler (C Programming Language) for this
I am not aware of any other invalid values in other headers, its just the ImageBase getting me frustrated.
A quick thing, if you also need to know what the function parameters for opening and mapping the file are then here they are:
HANDLE Func_TargetFile = CreateFileW((wchar_t*) & Func_ConsoleCommand, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
HANDLE Func_TargetFileMapping = CreateFileMappingW(Func_TargetFile, NULL, PAGE_READWRITE, 0, 0, NULL);
void* Func_TargetFileViewMap = MapViewOfFile(Func_TargetFileMapping, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 0);
That is all, once again if you are confused of what my question is: Why does the IMAGE_OPTIONAL_HEADER ImageBase gives me a value of 0 even though all other values in the header seem to match what CFF Explorer shows me? - Thank you
PS: I will check consistently, if you need more information then comment below.

I have solved the mistery, it was in the GetFilePEHeader function! The printed out value is now: 0x000000005F5E100
The issue was with the casting, this line of code:
return (IMAGE_NT_HEADERS*) ((char*) (Func_FileDOSHeader) + Func_FileDOSHeader->e_lfanew);
Here is the fixed function:
IMAGE_NT_HEADERS* FileUtils_GetFilePEHeader (void* Arg_FileViewMap) {
if (Arg_FileViewMap != NULL) {
IMAGE_DOS_HEADER* Func_FileDOSHeader = FileUtils_GetFileDOSHeader(Arg_FileViewMap);
if (Func_FileDOSHeader != NULL) {
return (IMAGE_NT_HEADERS*) ((INT64) Func_FileDOSHeader + Func_FileDOSHeader->e_lfanew);
}
}
return NULL;
}
Thank you all for all of your help, this was quite a dumb issue. It took me 3 days to figure this out.

Related

determining original cause of error

Is there some well known pattern/practice for nested error handling in C, something like nested exceptions in Java?
With the usual "just return error code/success" error details may be lost before a program can determine it should log/report error.
Imagine a code similar to this:
err B()
{
if (read(a/b/c/U.user) != OK) {
return read_error; //which would be eaccess or we could return even e_cannot_read_user
}
if (is_empty(read_user.name)) {
// we could tell exactly what is missing here
return einval;
}
...
}
err A()
{
if (B() != OK) {
if (cannot_handle_B_failing()) {
return e_could_not_do_b;
}
}
...
}
main()
{
...
if (A() != OK) && (no_alternative_solution()) {
report error_returned_by_A;
wait_for_more_user_input();
}
}
Has anyone successfully tried some kind of nested error codes/messages in C for situations like that? Something that could report (in main) the fact that user name was missing or that file F can not be read due to invalid permissions.
Is there a library to support something like this?
I would suggest you to look at Apple's error handling guideline. It was designed for Objective-C and the main class there is NSError. They are using a userInfo dictionary (map) for holding detailed info about the error, and they have predefined NSUnderlyingErrorKey constant for holding underlying NSError object in that dictionary if needed.
So you can declare your own error struct for your code and implement similar solution.
e.g.
typedef struct {
int code;
struct Error *underlyingError;
char domain[0];
} Error;
You can then use domain field to categorize errors (by libs, files or functions as you want); code field to determine error itself and optional underlyingError field to find out what underlying error caused the error you received.
Each function may have its own independent, documented, and isolated set of errors. Like each function from the libc have their own documented set of possible return values and ERRNO codes.
The "root cause" is only an implementation detail, you just have to know "why" it failed.
In other words, A's documentation should not explain B, should not tell it uses B, nor tell about B's errors codes, it can have its own, locally meaningful, error codes.
Also while trying alternatives, you'll have to keep the origin failure codes (locally), so if the alternatives also fail you'll still be able to know what caused you to try them in the first place.
err B()
{
if (read(a/b/c/U.user) != OK) {
return read_error; //which would be eaccess or we could return even e_cannot_read_user
}
if (is_empty(read_user.name)) {
// we could tell exactly what is missing here
return einval;
}
...
}
err A()
{
if ((b_result = B()) != OK) {
// Here we understand b_result as we know B,
// but outside of we will no longer understand it.
// It means that we have to map B errors
// to semantically meaningful A errors.
if (cannot_handle_B_failing()) {
if (b_result == …)
return e_could_not_do_b_due_to_…;
else if (b_result == …)
return e_could_not_do_b_due_to_…;
else
return e_could_not_do_b_dont_know_why;
}
}
...
}
main()
{
...
if ((a_result = A()) != OK) && (no_alternative_solution()) {
// Here, if A change its implementation by no longer calling B
// we don't care, it'll still work.
report a_result;
wait_for_more_user_input();
}
}
It's costly to map B's errors to A's errors, but there's a profit: when B will change its implementation, it won't break all A's call sites.
This semantical mapping may look useless at first ("I'll map a "permission denied" to a "permission denied"...) but has to be adapted to the current level of abstraction, typically from a "cannot open file" to an "cannot open configuration", like:
err synchronize(source, dest, conf) {
conf_file = open(conf);
if (conf == -1)
{
if (errno == EACCESS)
return cannot_acces_config;
else
return unexpected_error_opening_config_file;
}
if (parse(config_file, &config_struct) == -1)
return cannot_parse_config;
source_file = open(source);
if (source_file == -1)
{
if (errno == EACCESS)
return cannot_open_source_file;
else
return unexpected_error_opening_source_file;
}
dest_file = open(dest);
if (dest == -1)
{
if (errno == EACCESS)
return cannot_open_dest_file;
else
return unexpected_error_opening_dest_file;
}
}
And it does not have to be a one to one mapping. If you map errors one-to-one, for a depth of three functions, with three calls each, with the deeper function having 16 different possible errors, it'll map to 16 * 3 * 3 = 144 different distinct errors, which is just a maintenance hell for everyone (imagine your translators having to translate 144 error messages too… and your documentation listing and explaining them all, for a single function).
So, do not forget that functions have to abstract the work they're doing and also abstract the errors they encounter, to an understandable, locally meaningful, set of errors.
Finally, in some cases, even by keeping a whole stack trace of what happened, you won't be able to deduce the root cause of an error: Imagine a configuration reader have to look for configuration in 5 different places, it may encounter 3 "file not found", one "permission denied", and another "file not found", so it will return "Configuration not found". From here, nobody but the user can tell why it failed: Maybe the user did a typo in the first file name, and the permission denied was totally expected, or maybe the first three files are not meant to exist but the user did a chmod error on the 4th one.
In those cases, the only way to help the user debugging the issue is to provide verbose flags, like "-v" , "-vv", "-vvv", … each time adding a new level of debugging details, up to a point where the user will be able to see in the logs that the configuration had 5 places to check, checked the first one, got a file not found, and so on, and deduce where the program diverged from its intentions.
The solution we use in one of our project is to pass special error-handling struct thru full stack of functions. This allows to get original error and message on any higher level. Using this solution your example will look like:
struct prj_error {
int32_t err;
char msg[ERR_MAX_LEN];
};
prj_error_set(struct prj_error *err, int errorno, const char *fmt, ...); /* implement yourselves */
int B(struct prj_error *err)
{
char *file = "a/b/c/U.user";
if (custom_read(file) != OK) {
prj_error_set(err, errno, "Couldn't read file \"%s\". Error: %s\n",
file, strerror(errno));
return err->err;
}
if (is_empty(read_user.name)) {
prj_error_set(err, -ENOENT, "Username in file \"%s\" is empty\n",
file);
return err->err;
}
...
}
int A(struct prj_error *err)
{
if (B(err) != OK) {
if (cannot_handle_B_failing()) {
return err.err;
}
}
...
}
main()
{
struct prj_error err;
...
if (A(&err) != OK) && (no_alternative_solution()) {
printf("ERROR: %s (error code %d)\n", err.msg, err.err);
wait_for_more_user_input();
}
}
Good luck!
It's not a full solution, but what I tend to do is to have each compilation unit (C file) have unique return codes. It may have a couple of externally visible functions and a bunch of static (only locally visible) functions.
Then within the C file, the return values are unique. Within the C file, if it makes sense, I also decide if I need to log something. Whatever is returned, the caller can know exactly what went wrong.
None of this is great. OTOH exceptions also have wrinkles. When I code in C++ I don't miss C's return handling, but weirdly enough, when I code in C, I can not say with a straight face I miss exceptions. They add complexity in their own way.
My programs may look like this:
some_file.c:
static int _internal_function_one_of_a_bunch(int h)
{
// blah code, blah
if (tragedy_strikes()) {
return 13;
}
// blah more code
return 0; // OK
}
static int _internal_function_another(int h)
{
// blah code, blah
if (tragedy_strikes_again()) {
return 14;
}
if (knob_twitch() != SUPER_GOOD) {
return 15;
}
// blah more code
return 0; // OK
}
// publicly visible
int do_important_stuff(int a)
{
if (flight_status() < NOT_EVEN_OK) {
return 16;
}
return _internal_function_another(a) ||
_internal_function_one_of_a_bunch(2 * a) ||
0; // OK
}

WINAPI C - CreateFileMapping fails with error 8 - ERROR_NOT_ENOUGH_MEMORY

I'm working with file mappings on Windows but having some troubles with them.
First off, I have the necessity to partially map a file and setting the start and the end of it dynamically.
My code is the following:
long fiveMB = 5 * pow(2, 20);
for(int i=0;i<parts;i++){
long start = (i)*fiveMB;
long end = (i + 1)*fiveMB;
long realEnd = end;
if (roundedDim<realEnd)
realEnd = dim;
long chunkDim = realEnd - start;
LARGE_INTEGER fileMapStart.QuadPart = (start/granularity)*granularity;
LARGE_INTEGER mapViewSize.QuadPart = (start%granularity) + chunkDim;
LARGE_INTEGER fileMapSize.QuadPart = start + chunkDim;
long offset = start - fileMapStart.QuadPart;
HANDLE fileMappingH= CreateFileMapping(fileH, NULL, PAGE_READONLY, fileMapSize.HighPart, fileMapSize.LowPart, NULL);
if(fileMappingH == INVALID_HANDLE_VALUE || fileMappingH == NULL){
printf("Error mapping file: %d\n",GetLastError());
CloseHandle(fileH);
return 1;
}
char *mapView = (char *)MapViewOfFile(fileMappingH, FILE_MAP_READ, fileMapStart.HighPart, fileMapStart.LowPart, mapViewSize.QuadPart);
if ((LPVOID)mapView == NULL) {
printf("Error mapView: %d\n", GetLastError());
CloseHandle(fileMappingH);
CloseHandle(file);
return 1;
}
mapView += offset;
/* doing all the stuff */
UnmapViewOfFile((LPVOID)mapView);
CloseHandle(fileMappingH);
}
As far as I know, only MapViewOfFile requires the starting byte to be aligned with the system granularity, so I didn't bother to fix the maximum file mapping size for that.
I tried this code on a 1448 KB file (printing out dim I get 1482159 bytes) while calculating the available memory via GlobalMemoryStatusEx(&memstatus) and memstatus.ullAvailVirtual I get 2092208128 bytes but still stuck on having the CreateFileMapping call failed and with error code 8, ERROR_NOT_ENOUGH_MEMORY.
I also tried calling CreateFileMapping(fileH, NULL, PAGE_READONLY, 0, 0, NULL) to memory map the whole file, but instead there were problems on MapViewOfFile, error 5, ERROR_ACCESS_DENIED.
I don't understand what I'm doing wrong here, since I successfully did it with mmap on a Linux version of the same project.
Thanks anyone who may help.
EDITS:
c was a leftover, I actually meant i
added UnmapViewOfFile and CloseHandle calls
As far as I know, MapViewOfFile only requires the starting byte to be
aligned with the system granularity, so I didn't bother to fix the
maximum file mapping size for that.
this is root of error - really from MapViewOfFile
dwNumberOfBytesToMap [in]
The number of bytes of a file mapping to map to the view. All bytes
must be within the maximum size specified by CreateFileMapping. If
this parameter is 0 (zero), the mapping extends from the specified
offset to the end of the file mapping.
if we use 0 as MaximumSize in CreateFileMapping the maximum size of the file mapping object is equal to the current size of the file. and :
if an application specifies a size for the file mapping object that is
larger than the size of the actual named file on disk and if the
page protection allows write access (that is, the flProtect
parameter specifies PAGE_READWRITE or PAGE_EXECUTE_READWRITE),
then the file on disk is increased to match the specified size of the
file mapping object.
and about GetLastError and win32 errors at all. the errors in most case returned from kernel as NTSTATUS code. the win32 layer converts the specified NTSTATUS code to its equivalent system error code via RtlNtStatusToDosError. unfortunately this conversion not injective - the many different NTSTATUS code can convert to same win32 error and we lost sensitive info here.
so in some case much more better call RtlGetLastNtStatus() instead of GetlastError() - this give to as much more info about error.
CreateFileMapping call failed and with error code
ERROR_NOT_ENOUGH_MEMORY.
based on error ERROR_NOT_ENOUGH_MEMORY we can think that not enough memory in system (STATUS_NO_MEMORY). but also another status - STATUS_SECTION_TOO_BIG converted to the ERROR_NOT_ENOUGH_MEMORY. the CreateFileMapping is thin shell over ZwCreateSection the STATUS_SECTION_TOO_BIG returned when:
The value of MaximumSize is too big. This occurs when either
MaximumSize is greater than the system-defined maximum for sections, or if MaximumSize is greater than the specified file and the
section is not writable.
and this is exactly your case: you use PAGE_READONLY in call CreateFileMapping - so section is not writable and fileMapSize is greater than the specified file (size for the file mapping object that is larger than the size of the actual file on disk)
MapViewOfFile return ERROR_ACCESS_DENIED.
again GetLastError() plays here with us a cruel joke. the initial status is not STATUS_ACCESS_DENIED how we can wait, but STATUS_INVALID_VIEW_SIZE. this status also converted to ERROR_ACCESS_DENIED. the MapViewOfFile got it when not all bytes within the maximum size specified by CreateFileMapping
and call CreateFileMapping multiple time in loop - this is design error - need call this api only once, before loop. in loop only exist sense call MapViewOfFile. the test code can be:
void TestMap(PCWSTR lpFileName, ULONG dwChunkSize)
{
HANDLE hFile = CreateFileW(lpFileName, FILE_GENERIC_READ, FILE_SHARE_VALID_FLAGS, 0, OPEN_EXISTING, 0, 0);
if (hFile != INVALID_HANDLE_VALUE)
{
FILE_STANDARD_INFO fsi;
if (GetFileInformationByHandleEx(hFile, FileStandardInfo, &fsi, sizeof(fsi)))
{
if (HANDLE hSection = CreateFileMappingW(hFile, 0, PAGE_READONLY, 0, 0, 0))
{
if (ULONG n = (ULONG)((fsi.EndOfFile.QuadPart + (dwChunkSize - 1)) / dwChunkSize))
{
LARGE_INTEGER ofs = {};
do
{
if (PVOID pv = MapViewOfFile(hSection, FILE_MAP_READ, ofs.HighPart, ofs.LowPart, --n ? dwChunkSize : 0))
{
UnmapViewOfFile(pv);
}
else
{
RtlGetLastNtStatus();
}
} while (ofs.QuadPart += dwChunkSize, n);
}
CloseHandle(hSection);
}
else
{
RtlGetLastNtStatus();
}
}
CloseHandle(hFile);
}
else
{
RtlGetLastNtStatus();
}
}

SetupDiGetDeviceRegistryProperty: "The data area passed to a system call is too small" error

I have a code that enumerates USB devices on Windows XP using SetupAPI:
HDEVINFO hDevInfo = SetupDiGetClassDevs( &_DEVINTERFACE_USB_DEVICE, 0, 0, DIGCF_DEVICEINTERFACE | DIGCF_PRESENT);
for (DWORD i = 0; ; ++i)
{
SP_DEVINFO_DATA devInfo;
devInfo.cbSize = sizeof(SP_DEVINFO_DATA);
BOOL succ = SetupDiEnumDeviceInfo(hDevInfo, i, &devInfo);
if (GetLastError() == ERROR_NO_MORE_ITEMS)
break;
if (!succ) continue;
DWORD devClassPropRequiredSize = 0;
succ = SetupDiGetDeviceRegistryProperty(hDevInfo, &devInfo, SPDRP_COMPATIBLEIDS, NULL, NULL, 0, &devClassPropRequiredSize);
if (!succ)
{
// This shouldn't happen!
continue;
}
}
It used to work for years, but now I get FALSE from SetupDiGetDeviceRegistryProperty, last error is "The data area passed to a system call is too small".
It seems that my call parameters correspond to the documentation for this function: http://msdn.microsoft.com/en-us/library/windows/hardware/ff551967(v=vs.85).aspx
Any ideas what's wrong?
Problem was in your original code: SetupDiGetDeviceRegistryProperty function may return FALSE (and set last error to ERROR_INSUFFICIENT_BUFFER) when required property doesn't exist (or when its data is not valid, yes they have been lazy to pick a proper error code) so you should always check for ERROR_INSUFFICIENT_BUFFER as a (not so) special case:
DWORD devClassPropRequiredSize = 0;
succ = SetupDiGetDeviceRegistryProperty(
hDevInfo,
&devInfo,
SPDRP_COMPATIBLEIDS,
NULL,
NULL,
0,
&devClassPropRequiredSize);
if (!succ) {
if (ERROR_INSUFFICIENT_BUFFER == GetLastError() {
// I may ignore this property or I may simply
// go on, required size has been set in devClassPropRequiredSize
// so next call should work as expected (or fail in a managed way).
} else {
continue; // Cannot read property size
}
}
Usually you may simply ignore this error when you're reading property size (if devClassPropRequiredSize is still zero you can default it to proper constant for maximum allowed length). If property can't be read then next call SetupDiGetDeviceRegistryProperty will fail (and you'll manage error there) but often you're able to read value and your code will work smoothly.

How do I use Minizip (on Zlib)?

I'm trying to archive files for a cross-platform application, and it looks like Minizip (built on zlib) is about as portable as archivers come.
When I try to run the following dummy code, however, I get a system error [my executable] has stopped working. Windows can check online for a solution to the problem.
Can anyone help me see how to use this library? — (there's no doc or tutorial anywhere that I can find)
zip_fileinfo zfi;
int main()
{
zipFile zf = zipOpen("myarch.zip",APPEND_STATUS_ADDINZIP);
int ret = zipOpenNewFileInZip(zf,
"myfile.txt",
&zfi,
NULL, 0,
NULL, 0,
"my comment for this interior file",
Z_DEFLATED,
Z_NO_COMPRESSION
);
zipCloseFileInZip(zf);
zipClose(zf, "my comment for exterior file");
return 0;
}
Specs: Msys + MinGW, Windows 7, using zlibwapi.dll from zlib125dll.zip/dll32
Since I found this question via Google and it didn't contain any complete, working code, I am providing some here for future visitors.
int CreateZipFile (std::vector<wstring> paths)
{
zipFile zf = zipOpen(std::string(destinationPath.begin(), destinationPath.end()).c_str(), APPEND_STATUS_CREATE);
if (zf == NULL)
return 1;
bool _return = true;
for (size_t i = 0; i < paths.size(); i++)
{
std::fstream file(paths[i].c_str(), std::ios::binary | std::ios::in);
if (file.is_open())
{
file.seekg(0, std::ios::end);
long size = file.tellg();
file.seekg(0, std::ios::beg);
std::vector<char> buffer(size);
if (size == 0 || file.read(&buffer[0], size))
{
zip_fileinfo zfi = { 0 };
std::wstring fileName = paths[i].substr(paths[i].rfind('\\')+1);
if (S_OK == zipOpenNewFileInZip(zf, std::string(fileName.begin(), fileName.end()).c_str(), &zfi, NULL, 0, NULL, 0, NULL, Z_DEFLATED, Z_DEFAULT_COMPRESSION))
{
if (zipWriteInFileInZip(zf, size == 0 ? "" : &buffer[0], size))
_return = false;
if (zipCloseFileInZip(zf))
_return = false;
file.close();
continue;
}
}
file.close();
}
_return = false;
}
if (zipClose(zf, NULL))
return 3;
if (!_return)
return 4;
return S_OK;
}
The minizip library does come with examples; minizip.c for zipping and miniunz.c for unzipping. Both are command line utilities that show how to use the library. They are a mess though.
You also need to fill the zfi zip_fileinfo. At the very least you should initialize the structure to zero. zfi contains information about the file you want to store using zipOpenNewFileInZip. The structure should contain the date and attributes of "myfile.txt".
I recommend using PKWARE Desktop to diagnosis zip issues. It shows the structure/properties of the files in the ZIP and the ZIP file itself. When I opened the myarch.zip it told me there were errors. I drilled down into the file properties and found that the attributes were off.
The minizip lib is well documented. Just open the zip.h for details.
I can tell you here, you may have passed a wrong parameter for zipOpen. (APPEND_STATUS_ADDINZIP requires an existing zip file!)
Also, please check whether zipOpen returns a valid zipFile handle.

how to get off with the libxml2 error messages

I want to use the libxml2 lib to parse my xml files.
Now, when I have some bad xml file the lib itself is printing large error messages.
below is some sample code
reader = xmlReaderForFile(filename, NULL, 0);
if (reader != NULL) {
ret = xmlTextReaderRead(reader);
while (ret == 1) {
printf("_________________________________\n");
processNode(reader);
ret = xmlTextReaderRead(reader);
printf("_________________________________\n");
}
xmlFreeTextReader(reader);
if (ret != 0) {
fprintf(stderr, "%s : failed to parse\n", filename);
}
}
In above example, if I have bad xml file, I get error like this
my.xml:4: parser error : attributes construct error
include type="text"this is text. this might be excluded in the next occurrence
my.xml:4: parser error : Couldn't find end of Start Tag include
include type="text"this is text. this might be excluded in the next occurrence
my.xml : failed to parse
Instead, I just want to return some error no. and get off with this ugly lib messages.
what do I do ?
The last parameter to xmlReaderForFile(filename, NULL, 0); is a set of option flags. Reading the documentation for these flags, I see there are two options you might want to set: XML_PARSE_NOERROR and XML_PARSE_NOWARNING. Note that I haven't tried any of this, I just Googled libxml2 and xmlReaderForFile.
You will need to or the flags together like this:
reader = xmlReaderForFile(filename, NULL, XML_PARSE_NOERROR | XML_PARSE_NOWARNING);

Resources