No idea who came up with this, but it only needed a slight tidy up for it to show Exported Functions from a DLL
Brian
Tried program, works ok in the directory it starts in, but when I click on 'Folder' to switch over to the LIB directory for IWB, it just aborts. No error, just bombs.
Bill
Bill,
I did have some bother with the code, especially round Line 133, but I was able this morning to navigate to the \bin folder, and click through four DLLs there. Anyway, the code is not set up to see any .lib files, so they won't show. If anyone spots anything untoward, please let us all know
As I said, it is not my code, just a refresh of a previously written program by someone
Brian
Liked this one. Here's some code amended to check .lib files as well - Can be slow. For instance ntdll.lib with 2000+ exports takes more than 40 seconds to load.
autodefine "off"
$include "windowssdk.inc"
$include "stdio.inc"
$include "stdlib.inc"
CONST BTN_FOLDER = 1000
CONST LB_DLLS = 1001
CONST LV_1 = 1002
DECLARE EXTERN dup ALIAS _DUP$(path:POINTER),POINTER
DECLARE EXTERN _ibstrcpy(szdest:POINTER,szsrc:POINTER)
DIALOG d1
CREATEDIALOG d1,0,0,640,480,0x80CA0880,0,"Dll Viewer",&d1_handler
CONTROL d1,@LISTBOX,"",10,30,150,440,0x50B10143|@BORDER,LB_DLLS
CONTROL d1,@STATIC,"Select a DLL:",10,8,68,13,0x5000010B,2
CONTROL d1,@LISTVIEW,"",170,6,460,462,0x5081000D|@BORDER,LV_1
CONTROL d1,@BUTTON,"Folder...",90,4,70,20,0x50010000,BTN_FOLDER
DOMODAL d1
END
CONST SEM_FAILCRITICALERRORS = 1
SUB d1_handler(),INT
select @MESSAGE
case @IDINITDIALOG
CENTERWINDOW d1
SETCONTROLCOLOR d1,BTN_FOLDER,RGB(0,0,255),RGB(192,192,192)
ISTRING path[260]
' GetSystemDirectory(path,260)
path = "C:\Program Files (x86)\iwbdev\libs"
'path = "C:\Program Files (x86)\EBDev\libs"
EnumDLLs(d1,path)
ControlCmd(d1, LV_1, @LVINSERTCOLUMN,0,"#")
ControlCmd(d1, LV_1, @LVINSERTCOLUMN,1,"Function Pointer")
ControlCmd(d1, LV_1, @LVINSERTCOLUMN,2,"Function Name")
ControlCmd(d1, LV_1, @LVSETCOLWIDTH,0,35)
ControlCmd(d1, LV_1, @LVSETCOLWIDTH,1,100)
ControlCmd(d1, LV_1, @LVSETCOLWIDTH,2,-2)
SendMessage(d1, 0x1000 + 54,0,0x420,LV_1)
' if you try to LoadLibrary() with invalid image file the system displays the critical-error-handler message box
SetErrorMode(SEM_FAILCRITICALERRORS)
case @IDCLOSEWINDOW
FreeHeap(GetProp(d1.hWnd, "PATH"))
RemoveProp(d1.hWnd, "PATH")
CloseDialog(d1)
case @IDCONTROL
if (@CONTROLID = LB_DLLS) and (@NOTIFYCODE=@LBNSELCHANGE)
ShowDLLExports(d1, GetSelected(d1,LB_DLLS))
endif
/*add-on*/
if (@CONTROLID = BTN_FOLDER) and (@NOTIFYCODE=0)
_ibstrcpy(path, GetProp(d1.hWnd, "PATH"))
if FolderRequest(d1.hWnd, "Change Folder", path, path, 0)
FreeHeap(GetProp(d1.hWnd, "PATH"))
EnumDLLs(d1,path)
endif
endif
/*add-on*/
if (@CONTROLID = LV_1) and (@NOTIFYCODE=@LVNCOLUMNCLICK)
lvSort()
endif
endselect
return 0
ENDSUB
CONST LB_RESETCONTENT = 0x184
CONST LB_DIR = 0x18D
CONST DDL_ARCHIVE = 32
CONST DDL_HIDDEN = 2
CONST DDL_SYSTEM = 4
CONST WM_SETREDRAW = 0xB
Const LVM_SORTITEMSEX = 0x1000 + 81
' custom sum
CONST DDL_MY = DDL_ARCHIVE|DDL_HIDDEN|DDL_SYSTEM
SUB EnumDLLs(d1:WINDOW,path:STRING)
ControlCmd(d1, LV_1, @LVDELETEALL)
SetProp(d1.hWnd, "PATH", dup(path))
SendMessage(d1, LB_RESETCONTENT,0,0,LB_DLLS)
SendMessage(d1, LB_DIR, DDL_MY, path+"\\*.dll", LB_DLLS)
SendMessage(d1, LB_DIR, DDL_MY, path+"\\*.ax", LB_DLLS)
SendMessage(d1, LB_DIR, DDL_MY, path+"\\*.cpl", LB_DLLS)
SendMessage(d1, LB_DIR, DDL_MY, path+"\\*.acm", LB_DLLS)
SendMessage(d1, LB_DIR, DDL_MY, path+"\\*.ocx", LB_DLLS)
SendMessage(d1, LB_DIR, DDL_MY, path+"\\*.sys", LB_DLLS)
SendMessage(d1, LB_DIR, DDL_MY, path+"\\*.tsp", LB_DLLS)
SendMessage(d1, LB_DIR, DDL_MY, path+"\\*.xvd", LB_DLLS)
SendMessage(d1, LB_DIR, DDL_MY, path+"\\*.lib", LB_DLLS)
setcaption d1, path
ENDSUB
SUB ShowDLLExports(d1:WINDOW,index:INT)
' enumerates all exports of kernel32.dll
POINTER ImageBase
POINTER OH_pointer /*Optional Header*/
POINTER PE_pointer /*COFF File Header*/
POINTER EXP_pointer /*Export Table address*/
POINTER NamePointerRVA /* pointer to string* pointers array */
POINTER ExportAddressTableRVA
POINTER dir
POINTER pszFile
INT NumberOfNamePointers
ControlCmd(d1, LV_1, @LVDELETEALL)
dir = GetProp(d1.hWnd, "PATH")
pszFile = *<STRING>dir + "\\" + GetString(d1, LB_DLLS, index)
setcaption d1, *<STRING>pszFile
string extension = RIGHT$(*<string>pszFile, 3)
SELECT LCASE$(extension)
CASE "lib"
ShowlibExports(d1, *<STRING>pszFile)
RETURN
ENDSELECT
ImageBase = LoadLibrary(pszFile)
FreeHeap(pszFile)
if (ImageBase = 0)
SetCaption(d1, "Failed to load DLL")
return
endif
if left$(*<STRING>ImageBase, 2) <> "MZ"
SetCaption(d1, "Not Executable")
return
endif
PE_pointer = ImageBase + *<WORD>(ImageBase+0x3C)
if left$(*<STRING>PE_pointer, 4) <> "PE"
SetCaption(d1, "Not PE")
return
endif
PE_pointer += 4 /*COFF File Header*/
OH_pointer = PE_pointer + 20 /*Optional Header*/
EXP_pointer = ImageBase + *<UINT>(OH_pointer + 96) /*Export Table address*/
NumberOfNamePointers = *<UINT>(EXP_pointer + 24)
NamePointerRVA = ImageBase + *<UINT>(EXP_pointer + 32)
ExportAddressTableRVA = ImageBase + *<UINT>(EXP_pointer + 28)
ShowExports( _
d1, _
ImageBase, _
ExportAddressTableRVA, _
NamePointerRVA, _
NumberOfNamePointers)
FreeLibrary(ImageBase)
ENDSUB
SUB ShowlibExports(WINDOW d1, string fullpath)
INT item = 0
' do not repaint listview every time we add an item
SendMessage(d1, WM_SETREDRAW, FALSE, 0, LV_1)
pointer myfile = CreateFile(fullpath, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL)
IF myfile <> INVALID_HANDLE_VALUE THEN
DWORD dwFileSize = GetFileSize(myfile, NULL)
IF dwFileSize <> 0xFFFFFFFF THEN
LPSTR pszFileText = GlobalAlloc(GPTR, dwFileSize + 2)
IF pszFileText <> NULL THEN
DWORD dwRead = 0
IF ReadFile(myfile, pszFileText, dwFileSize, &dwRead, NULL) THEN
pointer p = pszFileText + 0
INT counter = 0
WHILE counter < dwRead - 10
counter++
p+=1
IF LEFT$(*<string>p, 6) = "__imp_" THEN
IF INSTR(lcase$(*<STRING>p), ".dll") = 0 THEN
IF LEN(*<STRING>p) > 7 THEN
string _line
strncpy(_line, *<STRING>p, 255)
'do something with the data
_line = MID$(_line, 7)
istring name[1000] = ""
' avoid duplicates...
INT count = CONTROLCMD(d1, LV_1, @LVGETCOUNT)
INT j
INT founded = 0
FOR j = 1 TO count
CONTROLCMD(d1, LV_1, @LVGETTEXT, j-1, 2, name, 1000)
IF INSTR(_line, name) THEN
founded = 1
BREAKFOR
ENDIF
next j
IF founded = 0 THEN
ControlCmd(d1, LV_1, @LVINSERTITEM, item, using(" #", item))
ControlCmd(d1, LV_1, @LVSETTEXT, item, 1, " ")
ControlCmd(d1, LV_1, @LVSETTEXT, item, 2, RTRIM$(_line))
item++
ENDIF
ENDIF
ENDIF
ENDIF
ENDWHILE
ENDIF
GlobalFree(pszFileText)
ENDIF
ENDIF
CloseHandle(myfile)
ENDIF
' listview will be always sorted as selected
SendMessage(d1, LVM_SORTITEMSEX, 0, &LVSortCallback3state, LV_1)
SendMessage(d1, WM_SETREDRAW, TRUE, 0, LV_1)
ENDSUB
SUB ShowExports(d1:WINDOW, ImageBase:UINT, fntable:POINTER, strtable:POINTER, count:INT)
INT item
' do not repaint listview every time we add an item
SendMessage(d1, WM_SETREDRAW, FALSE, 0, LV_1)
item=0
while count
if (*<INT>fntable < 0)
ControlCmd(d1, LV_1, @LVDELETEALL)
SetCaption(d1, "Error! Invalid Offset")
SendMessage(d1, WM_SETREDRAW, TRUE, 0, LV_1)
return
endif
ControlCmd(d1, LV_1, @LVINSERTITEM, item, using(" #", item))
ControlCmd(d1, LV_1, @LVSETTEXT, item, 1, "0x"+hex$(ImageBase + *<UINT>fntable))
ControlCmd(d1, LV_1, @LVSETTEXT, item, 2, *<STRING>(ImageBase + *<UINT>strtable))
fntable += 4
strtable+= 4
count--
item++
wend
' listview will be always sorted as selected
SendMessage(d1, LVM_SORTITEMSEX, 0, &LVSortCallback3state, LV_1)
SendMessage(d1, WM_SETREDRAW, TRUE, 0, LV_1)
ENDSUB
/* tools */
Declare import, SHBrowseForFolder(lpbi:POINTER),INT
Declare import, SHGetPathFromIDList(pITEMIDLIST:UINT, PATH:POINTER),INT
' fills memory with given character
$command _memset(...) /*(memory, char, count*/
const BFFM_INITIALIZED = 1
const BFFM_SETSELECTION = (0x400 + 102)
const BFFM_VALIDATEFAILED = 3
TYPE BROWSEINFO
UINT hOwner
UINT pidlRoot
POINTER pszDisplayName
POINTER lpszTitle
UINT ulFlags
UINT lpfn
UINT lParam
UINT iImage
ENDTYPE
SUB FolderRequest(hWnd:uint, title:pointer, dir:pointer, initial:pointer, flags:uint),int
INT r
r = FALSE
UINT item_list
BROWSEINFO bi
_memset(&bi, 0, len(bi))
bi.hOwner = hWnd
bi.lpszTitle = title
bi.ulFlags = flags
IF flags = 0 Then bi.ulFlags = 9 | 0x42
bi.lpfn = &BrowseRequestCallback
bi.lParam = initial
' Display the browser
item_list = SHBrowseForFolder(&bi)
IF item_list
r = SHGetPathFromIDList(item_list, dir)
CoTaskMemFree(item_list)
Endif
Return r
EndSub
SUB BrowseRequestCallback(hWnd:uint, uMsg:uint, lParam:uint, lpData:uint),int
' UINT dwStyle
' ISTRING szText[261]
Select uMsg
Case BFFM_INITIALIZED
' Set start directory
SendMessage hWnd, BFFM_SETSELECTION, TRUE, lpData
Case BFFM_VALIDATEFAILED
Return 1
EndSelect
Return 0
EndSub
'////////////// listview sorting function ///////////////
' move global variables to window property
INT LastClickedColumn, ClickedColumn, SortAscDesc
UINT LVhWnd
Const LVM_GETITEM = 4101
Const LVIF_TEXT = 1
TYPE NMLISTVIEW /*hacked!*/
NMHDR hdr
INT iItem
INT iSubItem[7]
ENDTYPE
TYPE LVITEM /*hacked!*/
UINT mask
INT iItem
INT iSubItem[3]
POINTER pszText
INT cchTextMax[7]
ENDTYPE
SUB lvSort()
INT ColumnChanged
ColumnChanged = 0
LVhWnd = *<NMHDR>@LPARAM.hWndFrom
ClickedColumn = *<NMLISTVIEW>@LPARAM.iSubItem
IF LastClickedColumn <> ClickedColumn
LastClickedColumn = ClickedColumn
SortAscDesc = 1
ColumnChanged = 1
Endif
IF ColumnChanged=0
SortAscDesc++
IF SortAscDesc = 2 Then SortAscDesc= -1
Endif
SendMessage(LVhWnd, LVM_SORTITEMSEX, 0, &LVSortCallback3state)
EndSub
SUB LVSortCallback3state(lParam1:int, lParam2:int, lParamSort:uint),int
LVITEM lvi1, lvi2
ISTRING txt1[260], txt2[260]
INT CompareResult
lvi1.iItem = lParam1
lvi2.iItem = lParam2
IF (SortAscDesc = 0)
lvi1.iSubItem = 0 'sort by first column
lvi2.iSubItem = 0 'else sort by clicked column
else
lvi1.iSubItem = ClickedColumn 'the last clicked column
lvi2.iSubItem = ClickedColumn 'the last clicked column
Endif
lvi1.mask = LVIF_TEXT
lvi2.mask = LVIF_TEXT
lvi1.pszText = &txt1
lvi2.pszText = &txt2
lvi1.cchTextMax = 260
lvi2.cchTextMax = 260
SendMessage(LVhWnd, LVM_GETITEM, 0, &lvi1)
SendMessage(LVhWnd, LVM_GETITEM, 0, &lvi2)
IF (SortAscDesc <> 0)
CompareResult = lstrcmpi(&txt1, &txt2)
CompareResult *= SortAscDesc
Else
CompareResult = val(txt1) > val(txt2) 'the first column is a numeric value
Endif
Return CompareResult
EndSub
I switched to a directory with only 1 dll in it, the program aborts on me, just basically shuts down after I select a folder.
Bill
Compiled Gabriel's listing, and changed directory about six times with no problems
Bill, I will put my compiled exe in Dropbox\cfImages for you
Brian
New version works fine on switching directorys, but when going to where I store my IWB source and have a DLL file, it pulls up the files, but not the stuff in them. Weird....
Bill
Gabriel,
When I list the ntdll.lib, it takes my PC about 17 seconds. You will have to get yourself one of those new-fangled PCs that don't run on steam and valves!
Brian
Bill, you are right. I can change from \libs to \bin and it shows the DLL names, but no exported functions
Brian
Quote from: undefinedWhen I list the ntdll.lib, it takes my PC about 17 seconds. You will have to get yourself one of those new-fangled PCs that don't run on steam and valves!
Currently, I have a lenovo notebook which never gave me a letdown (until now), it seems the processor is not that good at all! So I'll keep that in mind and I'll use those exact words when the need for a replacement arrives ;D
Quote from: undefinedBill, you are right. I can change from \libs to \bin and it shows the DLL names, but no exported functions
Did you guys by any chance are able to see any error message in the caption? The program seems to format in there some basic info when something goes wrong. Also any difference running the program as administrator?
Yes, it shows "Not Executable" when clicking on a file in the \bin folder. Running as Administrator makes no difference
Brian
Seems to be working OK now with this update, based on Fasecero's addition to read .lib files
Brian