Beispiel #1
0
bool GetExeInfo(LPCSTR fileName, ExeInfo&info)
{
	LOADED_IMAGE loadedImage;
	if (!MapAndLoad(const_cast<PSTR>(fileName), nullptr, &loadedImage, FALSE, TRUE))
	{
		return false;
	}

	info.managed = false;
	if (loadedImage.FileHeader->Signature == IMAGE_NT_SIGNATURE)
	{

		DWORD netHeaderAddress =
			loadedImage.FileHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress;

		if (netHeaderAddress)
		{
			info.managed = true;
		}
	}

	info.entryPoint = loadedImage.FileHeader->OptionalHeader.AddressOfEntryPoint;
	info.i386 = loadedImage.FileHeader->FileHeader.Machine == IMAGE_FILE_MACHINE_I386;

	UnMapAndLoad(&loadedImage);

	return true;
}
Beispiel #2
0
bool DebugFrontend::GetExeInfo(LPCSTR fileName, ExeInfo& info) const
{
    
    LOADED_IMAGE loadedImage;
    if (!MapAndLoad(const_cast<PSTR>(fileName), NULL, &loadedImage, FALSE, TRUE))
    {
        return false;
    }

    // Check if this is a managed application.
    // http://www.codeguru.com/cpp/w-p/system/misc/print.php/c14001

    info.managed = false;
    if (loadedImage.FileHeader->Signature == IMAGE_NT_SIGNATURE)
    {
       
        DWORD netHeaderAddress =
            loadedImage.FileHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress;

        if (netHeaderAddress)
        {
            info.managed = true;
        }
    
    }
    
    info.entryPoint = loadedImage.FileHeader->OptionalHeader.AddressOfEntryPoint;
    info.i386       = loadedImage.FileHeader->FileHeader.Machine == IMAGE_FILE_MACHINE_I386;

    UnMapAndLoad(&loadedImage);

    return true;

}
Beispiel #3
0
void KImageModule::Unload(void)
{
    SymUnloadModule(m_hProcess, m_symbolbase);
    SymCleanup(m_hProcess);

	if ( m_image.ModuleName )
		UnMapAndLoad(& m_image);
} 
// Given the path to our python executable, load the binary and check
// the processor architecture. If it's an x64 binary and our current
// executable isn't, we'll return 0.
static int is_valid(char* python)
{
	char sPythonDir[MAX_PATH+1] = {0};
	int result = 1;
	LOADED_IMAGE oImg;
	ZeroMemory(&oImg, sizeof(oImg));
	if(!get_parent_dir(python, sPythonDir, MAX_PATH)) {
		debug("Could not get parent folder of %s..", python);
		return 0;
	}
	if(!MapAndLoad(PYTHON_EXE, sPythonDir, &oImg, 0, 1)) {
		debug("Could not MapAndLoad %s. Used folder: %s", PYTHON_EXE, sPythonDir);
		return 0;
	}
	switch(oImg.FileHeader->FileHeader.Machine)
	{
		case IMAGE_FILE_MACHINE_IA64:
#ifdef _M_IA64
			result = 1;
#else
			result = 0;
			Platform_Mismatch("IA64");
#endif
			break;
		// AMD64
		case IMAGE_FILE_MACHINE_AMD64:
#ifdef _M_X64
			result = 1;
#else
			result = 0;
			Platform_Mismatch("X64");
#endif
			break;
		// X86 (32-bit)
		case IMAGE_FILE_MACHINE_I386:
#ifdef _M_IX86
			result = 1;
#else
			result = 0;
			Platform_Mismatch("X86");
#endif
			break;
		// IA64
		default:
			result = 0;
			Platform_Mismatch("Invalid");
			break;
	}
	// This shouldn't happen, but you never know.
	if(!UnMapAndLoad(&oImg)) {
		debug("Could not unmap the python image.");
		return 0;
	}
	return result;
}
Beispiel #5
0
int
main(int argc, char *argv[])
{
	util_suppress_errmsg();
	if (argc < 2) {
		fprintf(stderr, "usage: %s dllname\n", argv[0]);
		exit(1);
	}

	const char *dllname = argv[1];

	LOADED_IMAGE img;
	if (MapAndLoad(dllname, NULL, &img, 1, 1) == FALSE) {
		fprintf(stderr, "cannot load DLL image\n");
		exit(2);
	}

	IMAGE_EXPORT_DIRECTORY *dir;
	ULONG dirsize;
	dir = (IMAGE_EXPORT_DIRECTORY *)ImageDirectoryEntryToData(
			img.MappedAddress, 0 /* mapped as image */,
			IMAGE_DIRECTORY_ENTRY_EXPORT, &dirsize);
	if (dir == NULL) {
		fprintf(stderr, "cannot read image directory\n");
		UnMapAndLoad(&img);
		exit(3);
	}

	DWORD *rva;
	rva = (DWORD *)ImageRvaToVa(img.FileHeader, img.MappedAddress,
			dir->AddressOfNames, NULL);

	for (DWORD i = 0; i < dir->NumberOfNames; i++) {
		char *name = (char *)ImageRvaToVa(img.FileHeader,
				img.MappedAddress, rva[i], NULL);
		printf("%s\n", name);
	}

	UnMapAndLoad(&img);
	return 0;
}
Beispiel #6
0
BOOL TryMapAndLoad (PCSTR name, PCSTR path, PLOADED_IMAGE loadedImage, int requiredMachineType)
{
    BOOL success = MapAndLoad (name, path, loadedImage, FALSE, TRUE);
    if (!success && GetLastError () == ERROR_FILE_NOT_FOUND)
        success = MapAndLoad (name, path, loadedImage, TRUE, TRUE);
    if (success && requiredMachineType != -1 && (int)loadedImage->FileHeader->FileHeader.Machine != requiredMachineType)
    {
        UnMapAndLoad (loadedImage);
        return FALSE;
    }
    return success;
}
static BOOL
PatchImports(char* name)
{
  LOADED_IMAGE image;

  if (!MapAndLoad(name, NULL, &image, FALSE, FALSE)) {
	  fprintf(stderr, "couldn't MapAndLoad '%s'\n", name);
	  return FALSE;
  }

  if (image.FileHeader->OptionalHeader.NumberOfRvaAndSizes >= 2) {
    PIMAGE_IMPORT_DESCRIPTOR importDesc =
      (PIMAGE_IMPORT_DESCRIPTOR) GetPtrFromRVA(
        image.FileHeader->OptionalHeader.DataDirectory[1].VirtualAddress,
	image.FileHeader,
	image.MappedAddress);
    while(1) {
      char *s;
      int len;

      // We've reached an empty IMAGE_IMPORT_DESCRIPTOR?
      if ((importDesc->TimeDateStamp == 0) && (importDesc->Name==0)) {
	break;
      }

      s = (char *) GetPtrFromRVA(importDesc->Name,
				 image.FileHeader,
				 image.MappedAddress);

      len = strlen(s);
      if (!strcasecmp(s, "kernel32.dll") ||
	  !strcasecmp(s, "msvcrt.dll") ||
	  !strcasecmp(s, "user32.dll") ||
	  !strcasecmp(s, "gdi32.dll") ||
	  !strcasecmp(s, "ole32.dll") ||
	  !strcasecmp(s, "advapi32.dll") ||
	  !strcasecmp(s, "comctl32.dll") ||
	  !strcasecmp(s, "ntdll.dll")) {
	printf("...patching %s ->", s);
	s[len - 5] = '_';
	printf(" %s\n", s);
      }
	  
      importDesc++;
    }
  }

  UnMapAndLoad(&image);
  return TRUE;
}
Beispiel #8
0
static void
load_and_analyze(void *dcontext, char *dllname)
{
    LOADED_IMAGE img;
    BOOL res;

    res = MapAndLoad(dllname, NULL, &img, FALSE, TRUE);
    if (!res) {
        print("Error loading %s\n", dllname);
        return;
    }
    verbose_print("mapped at "PFX" (preferred "PFX")\n",
                  img.MappedAddress, get_preferred_base(&img));
    if (!list_usercalls)
        process_exports(dcontext, dllname, &img);
    if (list_syscalls || list_usercalls)
        process_symbols(dcontext, dllname, &img);
    UnMapAndLoad(&img);
}
CAppProtector::CAppProtector(const char *lpszProtectedFileName,const char *lpszOriginalPEImageName, CAppSecureDlg* t)
{
	ui=t;
	/*
	lpszProtectedFileName is the output filename, which is "SecureFile.EXE" by default
	lpszOriginalPEImageName is the PE File to protect. This file will NOT be modified in anyway.
	*/
	szProtectedFileName=new char[lstrlen(lpszProtectedFileName)+1];
	lstrcpy(szProtectedFileName,lpszProtectedFileName);
	szMyFileName=new char[lstrlen(lpszOriginalPEImageName)+1];
	lstrcpy(szMyFileName,lpszOriginalPEImageName);
	/////////////////////////////////////////////////////////////////////////
	LOADED_IMAGE li;
	if(MapAndLoad(szMyFileName,0,&li,FALSE,TRUE)) RVAToFileOffset(li.FileHeader,li.FileHeader->OptionalHeader.AddressOfEntryPoint,li.FileHeader->FileHeader.NumberOfSections);
    else
    {
        AfxMessageBox("Load Failed !");
        exit(1);
    }
	UnMapAndLoad(&li);
	/////////////////////////////////////////////////////////////////////////
}
Beispiel #10
0
/***********************************************************************
 *		BindImageEx (IMAGEHLP.@)
 *
 * Compute the virtual address of each function imported by a PE image
 *
 * PARAMS
 *
 *   Flags         [in] Bind options
 *   ImageName     [in] File name of the image to be bound
 *   DllPath       [in] Root of the fallback search path in case the ImageName file cannot be opened
 *   SymbolPath    [in] Symbol file root search path
 *   StatusRoutine [in] Pointer to a status routine which will be called during the binding process
 *
 * RETURNS
 *   Success: TRUE
 *   Failure: FALSE
 *
 * NOTES
 *  Binding is not implemented yet, so far this function only enumerates
 *  all imported dlls/functions and returns TRUE.
 */
BOOL WINAPI BindImageEx(
  DWORD Flags, PCSTR ImageName, PCSTR DllPath, PCSTR SymbolPath,
  PIMAGEHLP_STATUS_ROUTINE StatusRoutine)
{
    LOADED_IMAGE loaded_image;
    const IMAGE_IMPORT_DESCRIPTOR *import_desc;
    ULONG size;

    FIXME("(%d, %s, %s, %s, %p): semi-stub\n",
        Flags, debugstr_a(ImageName), debugstr_a(DllPath),
        debugstr_a(SymbolPath), StatusRoutine
    );

    if (!(MapAndLoad(ImageName, DllPath, &loaded_image, TRUE, TRUE))) return FALSE;

    if (!(import_desc = RtlImageDirectoryEntryToData((HMODULE)loaded_image.MappedAddress, FALSE,
                                                     IMAGE_DIRECTORY_ENTRY_IMPORT, &size)))
    {
        UnMapAndLoad(&loaded_image);
        return TRUE; /* No imported modules means nothing to bind, so we're done. */
    }

    /* FIXME: Does native imagehlp support both 32-bit and 64-bit PE executables? */
#ifdef _WIN64
    if (loaded_image.FileHeader->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR64_MAGIC)
#else
    if (loaded_image.FileHeader->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC)
#endif
    {
        FIXME("Wrong architecture in PE header, unable to enumerate imports\n");
        UnMapAndLoad(&loaded_image);
        return TRUE;
    }

    for (; import_desc->Name && import_desc->FirstThunk; ++import_desc)
    {
        IMAGE_THUNK_DATA *thunk;
        char dll_fullname[MAX_PATH];
        const char *dll_name;

        if (!(dll_name = ImageRvaToVa(loaded_image.FileHeader, loaded_image.MappedAddress,
                                      import_desc->Name, 0)))
        {
            UnMapAndLoad(&loaded_image);
            SetLastError(ERROR_INVALID_ACCESS); /* FIXME */
            return FALSE;
        }

        if (StatusRoutine)
            StatusRoutine(BindImportModule, ImageName, dll_name, 0, 0);

        if (!SearchPathA(DllPath, dll_name, 0, sizeof(dll_fullname), dll_fullname, 0))
        {
            UnMapAndLoad(&loaded_image);
            SetLastError(ERROR_FILE_NOT_FOUND);
            return FALSE;
        }

        if (!(thunk = ImageRvaToVa(loaded_image.FileHeader, loaded_image.MappedAddress,
                                   import_desc->OriginalFirstThunk ? import_desc->OriginalFirstThunk :
                                   import_desc->FirstThunk, 0)))
        {
            ERR("Can't grab thunk data of %s, going to next imported DLL\n", dll_name);
            continue;
        }

        for (; thunk->u1.Ordinal; ++thunk)
        {
            /* Ignoring ordinal imports for now */
            if(!IMAGE_SNAP_BY_ORDINAL(thunk->u1.Ordinal))
            {
                IMAGE_IMPORT_BY_NAME *iibn;

                if (!(iibn = ImageRvaToVa(loaded_image.FileHeader, loaded_image.MappedAddress,
                                          thunk->u1.AddressOfData, 0)))
                {
                    ERR("Can't grab import by name info, skipping to next ordinal\n");
                    continue;
                }

                if (StatusRoutine)
                    StatusRoutine(BindImportProcedure, ImageName, dll_fullname, 0, (ULONG_PTR)iibn->Name);
            }
        }
    }

    UnMapAndLoad(&loaded_image);
    return TRUE;
}
Beispiel #11
0
int BuildDepTree (BuildTreeConfig* cfg, char *name, struct DepTreeElement *root, struct DepTreeElement *self)
{
  LOADED_IMAGE loaded_image;
  LOADED_IMAGE *img;
  IMAGE_DOS_HEADER *dos;
  HMODULE hmod;
  BOOL success;

  DWORD i, j;
  int soffs_len;
  soff_entry *soffs;

  if (self->flags & DEPTREE_PROCESSED)
  {
    return 0;
  }

  if (cfg->on_self)
  {
    char modpath[MAX_PATH];
    success = GetModuleHandleExA (GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, name, &hmod);
    if (!success)
      return 1;
    if (GetModuleFileNameA (hmod, modpath, MAX_PATH) == 0)
      return 1;
    if (self->resolved_module == NULL)
      self->resolved_module = strdup (modpath);

    dos = (IMAGE_DOS_HEADER *) hmod;
    loaded_image.FileHeader = (IMAGE_NT_HEADERS *) ((char *) hmod + dos->e_lfanew);
    loaded_image.Sections = (IMAGE_SECTION_HEADER *) ((char *) hmod + dos->e_lfanew + sizeof (IMAGE_NT_HEADERS));
    loaded_image.NumberOfSections = loaded_image.FileHeader->FileHeader.NumberOfSections;
    loaded_image.MappedAddress = (void *) hmod;
    if (cfg->machineType != -1 && (int)loaded_image.FileHeader->FileHeader.Machine != cfg->machineType)
        return 1;
  }
  else
  {
    success = FALSE;
    for (i = 0; i < cfg->searchPaths->count && !success; ++i)
    {
      success = TryMapAndLoad (name, cfg->searchPaths->path[i], &loaded_image, cfg->machineType);
    }
    if (!success)
        success = TryMapAndLoad (name, NULL, &loaded_image, cfg->machineType);
    if (!success)
    {
      self->flags |= DEPTREE_UNRESOLVED;
      return 1;
    }
    if (self->resolved_module == NULL)
      self->resolved_module = strdup (loaded_image.ModuleName);
  }
  if (cfg->machineType == -1)
    cfg->machineType = (int)loaded_image.FileHeader->FileHeader.Machine;
  img = &loaded_image;

  PushStack (cfg->stack, cfg->stack_len, cfg->stack_size, name);

  self->mapped_address = loaded_image.MappedAddress;

  self->flags |= DEPTREE_PROCESSED;

  soffs_len = img->NumberOfSections;
  soffs = (soff_entry *) malloc (sizeof(soff_entry) * (soffs_len + 1));
  for (i = 0; i < img->NumberOfSections; i++)
  {
    soffs[i].start = img->Sections[i].VirtualAddress;
    soffs[i].end = soffs[i].start + img->Sections[i].Misc.VirtualSize;
    if (cfg->on_self)
      soffs[i].off = img->MappedAddress/* + img->Sections[i].VirtualAddress*/;
    else if (img->Sections[i].PointerToRawData != 0)
      soffs[i].off = img->MappedAddress + img->Sections[i].PointerToRawData - 
          img->Sections[i].VirtualAddress;
    else
      soffs[i].off = NULL;
  }
  soffs[img->NumberOfSections].start = 0;
  soffs[img->NumberOfSections].end = 0;
  soffs[img->NumberOfSections].off = 0;

  BuildDepTree32or64 (img, cfg, root, self, soffs, soffs_len);
  free (soffs);

  if (!cfg->on_self)
    UnMapAndLoad (&loaded_image);

  /* Not sure if a forwarded export warrants an import. If it doesn't, then the dll to which the export is forwarded will NOT
   * be among the dependencies of this dll and it will be necessary to do yet another ProcessDep...
  for (i = 0; i < self->exports_len; i++)
  {
    if (self->exports[i]->forward_str != NULL && self-.exports[i]->forward == NULL)
    {
      char *forward_str_copy = NULL, *export_name = NULL, *rdot = NULL;
      DWORD export_ordinal = 0;
      forward_str_copy = strdup (self->exports[i]->forward_str);
      rdot = strrchr (forward_str_copy, '.');
      if (rdot != NULL && rdot[1] != 0)
      {
        rdot[0] = 0;
        export_name = &rdot[1];
        if (export_name[0] == '#' && export_name[1] >= '0' && export_name[1] <= '9')
        {
          export_ordinal = strtol (&export_name[1], NULL, 10);
          export_name = NULL;
        }
        self->exports[i]->forward = FindExportForward (forward_str_copy, export_name, export_ordinal);
      }
      free (forward_str_copy);
    }
  }
  */
  for (i = 0; i < self->imports_len; i++)
  {
    if (self->imports[i].mapped == NULL && self->imports[i].dll != NULL && (self->imports[i].name != NULL || self->imports[i].ordinal > 0))
    {
      struct DepTreeElement *dll = self->imports[i].dll;
      for (j = 0; j < dll->exports_len; j++)
      {
        if ((self->imports[i].name != NULL && dll->exports[j].name != NULL && strcmp (self->imports[i].name, dll->exports[j].name) == 0) ||
            (self->imports[i].ordinal > 0 && dll->exports[j].ordinal > 0 && self->imports[i].ordinal == dll->exports[j].ordinal))
        {
          self->imports[i].mapped = &dll->exports[j];
          break;
        }
      }
/*
      if (self->imports[i].mapped == NULL)
        printf ("Could not match %s (%d) in %s to %s\n", self->imports[i].name, self->imports[i].ordinal, self->module, dll->module);
*/
    }
  }
  /* By keeping items in the stack we turn it into a list of all
   * processed modules, this should be more effective at preventing
   * us from processing modules multiple times
   */
  /*PopStack (stack, stack_len, stack_size, name);*/
  return 0;
}
int WINAPI wWinMain(HINSTANCE hInstance,
	HINSTANCE hPrevInstance,
	LPWSTR lpOriginalCmdLine,
	int nCmdShow)
{
	int i;
	LOADED_IMAGE oImg;
	LPWSTR lpCmdLine;
	wchar_t parentDir[MAX_PATH+1] = L"", exePath[MAX_PATH+1] = L"";
	size_t szParentDir, szExeStr, szCmdLine, szPlatExe;
	PROCESS_INFORMATION pi;
	STARTUPINFO si;
	LPWSTR *argv = __wargv;
	int argc = __argc;

	// Zero out our loaded image struct.
	ZeroMemory(&oImg, sizeof(oImg));

	/* Make sure we have args. */
	if(argc == 1) {
		Fatal(1L, L"No images specified.");
	}
	

	/* Get our exe's parent folder. */
	if(!GetParentDir(parentDir, &szParentDir)) {
		Fatal(1L, L"Could not get parent folder of image, \"%s\". This should not happen ever.", argv[0]);
	}

	/* Iterate through our arguments */
	for(i = 1; i < argc; i++) {
		/* Verify file exists. */
		if(_waccess(argv[i], 00) == -1) {
			Fatal(1L, L"File does not exist.\nFile: %s", argv[i]);
		}

		/* Get the binary type. */
		if(!MapAndLoadW(argv[i], &oImg)) {
			Fatal(1L, L"Unable to get binary type for image.\nImage: %s", argv[i]);
		}

		lstrcpyW(exePath, parentDir);
		switch(oImg.FileHeader->FileHeader.Machine)
		{
			case IMAGE_FILE_MACHINE_I386:
				lstrcatW(exePath, x86exe);
				szPlatExe = SZ_86_EXE;
				break;
			// TODO: Differentiate between x64 platforms.
			case IMAGE_FILE_MACHINE_AMD64:
				lstrcatW(exePath, amd64exe);
				szPlatExe = SZ_AMD_EXE;
				break;
			case IMAGE_FILE_MACHINE_IA64:
				lstrcatW(exePath, ia64exe);
				szPlatExe = SZ_IA_EXE;
				break;
			default:
				Fatal(1L, L"Unknown binary type returned for image.\nImage: %s\n\nBinary Type: %d", argv[i], oImg.FileHeader->FileHeader.Machine);
		}

		if(!UnMapAndLoad(&oImg)) {
			Fatal(1L, L"Failed to unload/unmap image.\nImage: %s", argv[i]);
		}

		/* Calculate the length of the eventual exe path with surrounding quotes. */
		lstrcatW(exePath, depsexe);
		szExeStr = szParentDir + szPlatExe + 2; // +2 for the two "s surrounding the image path.

		/* Allocate our command line string. */
		// szExeStr+         1 +1+wcslen(argv)+1
		// "(path)depends.exe" "argv"
		szCmdLine = szExeStr + lstrlenW(argv[i]) + 3;
		lpCmdLine = (LPWSTR)LocalAlloc(LPTR, sizeof(wchar_t) * (szCmdLine + 1));
		if(lpCmdLine == NULL) {
			Fatal(1L, L"Could not allocate memory.\nMemory required (bytes): %d", sizeof(wchar_t) * (szCmdLine + 1));
		}
		if(swprintf(lpCmdLine, szCmdLine+1, L"\"%s\" \"%s\"", exePath, argv[i]) == -1) {
			LocalFree(lpCmdLine);
			FatalCall(L"swprintf");
		}

		ZeroMemory(&si, sizeof(si));
		si.cb = sizeof(si);
		ZeroMemory(&pi, sizeof(pi));

		/* Depends launching. */
		if (!CreateProcessW(
			NULL,		/* No module name (use command line) */
			lpCmdLine,	/* Command line */
			NULL,		/* Process handle not inheritable */
			NULL,		/* Thread handle not inheritable */
			FALSE,		/* Set handle inheritance to FALSE */
			0,			/* No creation flags */
			NULL,		/* Use parent's environment block */
			NULL,		/* Use parent's starting directory */
			&si,		/* Pointer to STARTUPINFO structure */
			&pi			/* Pointer to PROCESS_INFORMATION structure */
		)) {
			// len("CreateProcessW") + len(" - ") + len(cmdline)
			szCmdLine += 17;
			LocalFree(lpCmdLine);
			lpCmdLine = (LPWSTR)LocalAlloc(LPTR, sizeof(wchar_t) * (szCmdLine + 1));
			swprintf(lpCmdLine, szCmdLine+1, L"CreateProcessW - \"%s\" \"%s\"", exePath, argv[i]);
			FatalCall(lpCmdLine);
		}
		LocalFree(lpCmdLine);
	}
	return 0;
}
Beispiel #13
0
static void
process_exports(void *dcontext, char *dllname)
{
    LOADED_IMAGE img;
    IMAGE_EXPORT_DIRECTORY *dir;
    IMAGE_SECTION_HEADER *sec;
    DWORD *name, *code;
    WORD *ordinal;
    const char *string;
    uint size;
    BOOL res;
    uint i;
    byte *addr, *start_exports, *end_exports;

    verbose_print("Processing exports of \"%s\"\n", dllname);
    res = MapAndLoad(dllname, NULL, &img, FALSE, TRUE);
    if (!res) {
        print("Error loading %s\n", dllname);
        return;
    }
    dir = (IMAGE_EXPORT_DIRECTORY *)
        ImageDirectoryEntryToData(img.MappedAddress, FALSE,
                                  IMAGE_DIRECTORY_ENTRY_EXPORT, &size);
    verbose_print("mapped at 0x%08x, exports is at 0x%08x, size is 0x%x\n",
                  img.MappedAddress, dir, size);
    start_exports = (byte *) dir;
    end_exports = start_exports + size;
    verbose_print("name=%s, ord base=0x%08x, names=%d 0x%08x\n",
                  (char *) ImageRvaToVa(img.FileHeader, img.MappedAddress,
                                        dir->Name, NULL),
                  dir->Base, dir->NumberOfNames, dir->AddressOfNames);

    /* don't limit functions to lie in .text -- 
     * for ntdll, some exported routines have their code after .text, inside
     * ECODE section!
     */
    sec = img.Sections;
    for (i = 0; i < img.NumberOfSections; i++) {
        verbose_print("Section %d %s: 0x%x + 0x%x == 0x%08x through 0x%08x\n",
                      i, sec->Name, sec->VirtualAddress, sec->SizeOfRawData,
                      ImageRvaToVa(img.FileHeader, img.MappedAddress,
                                   sec->VirtualAddress, NULL),
                      (uint) ImageRvaToVa(img.FileHeader, img.MappedAddress,
                                          sec->VirtualAddress, NULL) +
                      sec->SizeOfRawData);
        sec++;
    }

    name = (DWORD *) ImageRvaToVa(img.FileHeader, img.MappedAddress,
                                  dir->AddressOfNames, NULL);
    code = (DWORD *) ImageRvaToVa(img.FileHeader, img.MappedAddress,
                                  dir->AddressOfFunctions, NULL);
    ordinal = (WORD *) ImageRvaToVa(img.FileHeader, img.MappedAddress,
                                    dir->AddressOfNameOrdinals, NULL);
    verbose_print("names: from 0x%08x to 0x%08x\n",
                  ImageRvaToVa(img.FileHeader, img.MappedAddress, name[0], NULL),
                  ImageRvaToVa(img.FileHeader, img.MappedAddress,
                               name[dir->NumberOfNames-1], NULL));

    for (i = 0; i < dir->NumberOfNames; i++) {
        string = (char *) ImageRvaToVa(img.FileHeader, img.MappedAddress, name[i], NULL);
        /* ordinal is biased (dir->Base), but don't add base when using as index */
        assert(dir->NumberOfFunctions > ordinal[i]);
        /* I don't understand why have to do RVA to VA here, when dumpbin /exports
         * seems to give the same offsets but by simply adding them to base we
         * get the appropriate code location -- but that doesn't work here...
         */
        addr = ImageRvaToVa(img.FileHeader, img.MappedAddress,
                            code[ordinal[i]], NULL);
        verbose_print("name=%s 0x%08x, ord=%d, code=0x%x -> 0x%08x\n",
                      string, string, ordinal[i], code[ordinal[i]], addr);
        if (list_exports) {
            print("ord %3d offs 0x%08x %s\n", ordinal[i],
                  addr - img.MappedAddress, string);
        }
        if (list_Ki && string[0] == 'K' && string[1] == 'i') {
            print("\n==================================================\n");
            print("%s\n\n", string);
            check_Ki(string);
            print("\ndisassembly:\n");
            decode_function(dcontext, addr);
            print(  "==================================================\n");
        }
        /* forwarded export points inside exports section */
        if (addr >= start_exports && addr < end_exports) {
            if (list_forwards || verbose) {
                /* I've had issues w/ forwards before, so avoid printing crap */
                if (addr[0] > 0 && addr[0] < 127)
                    print("%s is forwarded to %.128s\n", string, addr);
                else
                    print("ERROR identifying forwarded entry for %s\n", string);
            }
        } else if (list_syscalls) {
            process_syscall_wrapper(dcontext, addr, string, "export");
        }
    }

    if (list_syscalls)
        process_symbols(dcontext, dllname, &img);

    UnMapAndLoad(&img);
}