晚上没什么事情做,正好又断网了,无聊就做了个迷你型的程序。
起初是想用纯手搓,C32结合OD来做,但是输入表那一块我想不起来了,又不能上网查,只好偷个懒,用VC先做个典型的小文件,然后我再去修改。
这个小东西只有一个功能,快速关机,相信很多朋友都知道XP系统的任务管理器,有一个关机的选项,按住Ctrl点关机,会马上关上。
与正常关机的区别就是:普通关机会结束所有进程,关闭所有窗口,保存所有数据,然后断电。快速关机就是不保存临时数据,执行必要关机流程之后断电。
所以,在我看来,只要是事先保存好了自己的所有数据后,采用快速关机的方法是可行的。
用VC来实现这个功能只需要一分钟,大家看了这个就明白了。
typedef enum _SHUTDOWN_ACTION
{
ShutdownNoReboot,
ShutdownReboot,
ShutdownPowerOff
} SHUTDOWN_ACTION;
NTOSAPI NTSTATUS NTAPI NtShutdownSystem(IN SHUTDOWN_ACTION Action);
这个函数被ntdll.dll导出了,所以直接拿来用即可。
但是我想把这个文件做到最小,这是VC所不能做到的,所以VC先做,我再做。
关于PE文件格式不懂的朋友可以先搜索一下,你就知道。
最小的PE文件是0x400字节,也就是1KB,PE头部(DOS头+NT头+区段信息)=0x200字节,区段=0x200字节。
这不能满足我的要求,还得用输入表,再加一个区段,所以最后我做出来的文件有0x600字节=1536字节=1.5KB。
可能有朋友会说,把代码段和输入表合并不就省下来一个区段了吗?结果证明0x200的空间写的代码确实不多,没那么多空间。
前言就那么多了,下面就开始干活:
新建个空Win32工程,代码如下
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#include "ntapi.h"
#pragma comment(linker, "/OPT:NOWIN98")
BOOL WINAPI DebugPrivilege(LPCTSTR PName)
{
BOOL bResult = TRUE;
HANDLE hToken;
TOKEN_PRIVILEGES TokenPrivileges;
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY|TOKEN_ADJUST_PRIVILEGES, &hToken))
{
bResult = FALSE;
return bResult;
}
TokenPrivileges.PrivilegeCount = 1;
TokenPrivileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
LookupPrivilegeValueW(NULL, PName, &TokenPrivileges.Privileges[0].Luid);
AdjustTokenPrivileges(hToken, FALSE, &TokenPrivileges, sizeof(TOKEN_PRIVILEGES), NULL, NULL);
if (GetLastError() != ERROR_SUCCESS)
{
bResult = FALSE;
}
CloseHandle(hToken);
return bResult;
}
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nShowCmd)
{
if (DebugPrivilege(NULL) == FALSE)
{
MessageBoxW(NULL, NULL, NULL, NULL);
}
else
{
if (MessageBoxW(NULL, NULL, NULL, MB_YESNO) == IDYES)
{
NtShutdownSystem(ShutdownPowerOff);
}
}
return 0;
}
指定入口点,Release编译之后文件大小应该是2KB,距离目标很近了。
代码中没有使用字符串,因为用了之后文件还会增加一个区段,而这些字符串可以和代码段合并在一起。
现在与实现目标相差0x200字节,这个时候用C32打开,看到PE头部占用了0x400,多了0x200,而实际使用的数据只有0x200多一点点。
这就是MS的规定啊,必须要与0x200对齐,哪怕是0x201也得用0x400的空间。
浓缩一下,把DOS头精简,先清理DOS头的无用信息,然后移动NT头(网上叫PE头),修改PE头部大小数据,第一步OK。
现在这个文件物理偏移从0x200到0x400都是空白的了,括起来,DELETE,然后修改区段的偏移信息。
第一个区段,text,PointerToRawData数据原来是0x400,改成0x200,第二个区段rdata,原来是0x600,改成0x400,第二步OK。
保存,这个时候文件的大小就是1.5KB了,已经满足要求了。
接下来就是填入字符串数据,在代码段用OD写进去,再修正相应的PUSH指令即可。
现在,可以算是完工了,最小巧的实用型快速关机软件,哈哈。
------------------------------------------------------
我又继续做了些别的,把代码段全部NOP填充,重新自己写了反汇编代码,反正就俩函数,对比原来的反汇编和程序代码,好弄的很。
而且我发现自己写反汇编有点感觉了。
过程我就不说了,就是堆栈,内存,API,看的多了就好写了,直接上图。