首先感谢看雪举办这次活动,同时也祝愿看雪越走越好!
下面简单说下我的pediy如何实现 12 字节的 OpenUlrA , 大侠 见笑了哈
1,找一个最短的api函数实现打开网页的功能,查了下打开网页的api 只有 ShellExecuteA和WinExec这两个api可以用,这里我试了下winexec只能14个字节,ShellExecuteA要25个字节,呵呵,还没有比这两个更小的呢?答案是肯定的,运气呀,跟了下ShellExecuteA函数,惊奇的发现里面调用了一个函数ShellExecuteExA,而且只有一个参数,查了一下msdn 函数声明如下:
BOOL ShellExecuteExA(
LPSHELLEXECUTEINFO lpExecInfo
);
typedef struct _SHELLEXECUTEINFO{
DWORD cbSize;
ULONG fMask;
HWND hwnd;
LPCTSTR lpVerb;
LPCTSTR lpFile;
LPCTSTR lpParameters;
LPCTSTR lpDirectory;
int nShow;
HINSTANCE hInstApp;
// Optional members
LPVOID lpIDList;
LPCTSTR lpClass;
HKEY hkeyClass;
DWORD dwHotKey;
union {
HANDLE hIcon;
HANDLE hMonitor;
} DUMMYUNIONNAME;
HANDLE hProcess;
} SHELLEXECUTEINFO, *LPSHELLEXECUTEINFO;
参数是一个SHELLEXECUTEINFO结构的指针,SHELLEXECUTEINFO大小60个字节,在跟ShellExecuteA的过程中发现lpVerb就是ShellExecuteA的第二个参数,lpFile就是ShellExecuteA第三个参数,其他的都是固定的,内容如下:
008D3080 3C 00 00 00 00 15 00 00 00 00 00 00
78 30 8D 00 <..........x0?
008D3090
60 30 8D 00 00 00 00 00 00 00 00 00 05 00 00 00 `0?...........
008D30A0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
008D30B0 00 00 00 00 00 00 00 00 00 00 00 00 ............
蓝色就是lpVerb,红色就是lpFile,这么一来可以把这些内容用winhex编辑,放到date段里面,然后把
lpVerb和lpFile这两个 重定位一下,就ok了, 代码如下:
008D10D0 >/$ 68 80308D00 push 008D3080
008D10D5 |. FF15 14208D00 call dword ptr [<&SHELL32.ShellExecutExA>; SHELL32.ShellExecuteExA
008D10DB \. C3 retn
总字节12,比WinExec还小2个,呵呵,不知道还有没有更小
2,下面开始进行pe编辑了,经过上面分析还有题目的要求,需要 增加一个导入函数 ShellExecutExA 和 一个导出函数 OpenUrlA, 还需要 重定位:ShellExecutExA的参数,ShellExecutExA 函数,SHELLEXECUTEINFO结构中的 lpVerb和lpFile 一共四个,这里要注意 ,具体操作方法,很复杂,不好意思,我不知道怎么写了,发几个结构吧
导出表结构:
typedef struct _IMAGE_EXPORT_DIRECTORY {
Dword Characteristics;
Dword TimeDateStamp;
word MajorVersion;
word MinorVersion;
Dword Name;
Dword Base;
Dword NumberOfFunctions;
Dword NumberOfNames;
Dword AddressOfFunctions; // RVA from base of image
Dword AddressOfNames; // RVA from base of image
Dword AddressOfNameOrdinals; // RVA from base of image
} IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY;
IMAGE_EXPORT_DIRECTORY 结构成员含义:
1.Characteristics:此域没有用途,总是为0。
2.TimeDateStamp:程序被生成的时刻。
3.MajorVersion/MinorVersion:无实际用途,0。
4.Name:一个 RVA 值,指向一个 ASCIIZ 字串(dll 名称,如MYDLL.dll)。模块的真实名称。本域是必须的,因为文件名可能会改变。这种情况下,PE装载器将使用这个内部名字。
3.Base:基数,加上序数就是函数地址数组的索引值了。
4.NumberOfFunctions:模块导出的函数/符号总数。
5.NumberOfNames:通过名字导出的函数/符号数目。该值不是模块导出的函数/符号总数,这是由上面的NumberOfFunctions给出。本域可以为0,表示模块可能仅仅通过序数导出。如果模块根本不导出任何函数/符号,那么数据目录中导出表的RVA为0。
6.AddressOfFunctions:模块中有一个指向所有函数/符号的RVAs数组,本域就是指向该RVAs数组的RVA。简言之,模块中所有函数的RVAs都保存在一个数组里,本域就指向这个数组的首地址。
7.AddressOfNames:类似上个域,模块中有一个指向所有函数名的RVAs数组,本域就是指向该RVAs数组的RVA。
9.AddressOfNameOrdinals:RVA,指向包含上述 AddressOfNames数组中相关函数之序数的16位数组。
导入表结构:
typedef struct _IMAGE_IMPORT_DESCRIPTOR {
union {
Dword Characteristics; // 0 for terminating null import descriptor
Dword OriginalFirstThunk; // RVA to original unbound IAT (PIMAGE_THUNK_DATA)
};
Dword TimeDateStamp; // 0 if not bound,
// -1 if bound, and real date\time stamp
// in IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT (new BIND)
// O.W. date/time stamp of DLL bound to (Old BIND)
Dword ForwarderChain; // -1 if no forwarders
Dword Name;
Dword FirstThunk; // RVA to IAT (if bound this IAT has actual addresses)
} IMAGE_IMPORT_DESCRIPTOR;
IMAGE_IMPORT_DESCRIPTOR 结构成员含义:
1.结构第一项是一个union子结构。事实上,这个union子结构只是给 OriginalFirstThunk 增添了个别名,您也可以称其为"Characteristics"。该成员项含有指向一个 IMAGE_THUNK_DATA 结构数组的RVA。
2.TimeDateStamp:程序生成的时刻。此域通常为0。微软的 BIND 程序可以将此 IMAGE_IMPORT_DESCRIPTOR 所对应的dll的生成时刻写到这里来。
3.ForwarderChain:此域涉及到 forwarding(转交),意味着一个dll 函数在调用另一个 dll。例如,在 WINNT 中,Kernel32.dll 将它的某些输出函数转交给 NTDLL.dll。应用程序可能以为它调用 Kernel32.dll,而事实上它调用的事NTDLL.dll。这个域中含有一个索引,指向 FirstThunk 数组。被这个索引所指定的函数就是一个转交函数。
3.Name:含有指向DLL名字的RVA,即指向DLL名字的指针,也是一个ASCII字符串。
4.FirstThunk:与 OriginalFirstThunk 非常相似,它也包含指向一个 IMAGE_THUNK_DATA 结构数组的RVA(当然这是另外一个IMAGE_THUNK_DATA 结构数组)。
完
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)