资料"<<windows核心编程>>
你不会C,那先找本C的书...如果想要电子书的可以回帖留下你的Email,有空发给你,一些
自己珍藏的书籍
还有你应有VC++6.0和MSDN
好了,开始吧
目录
0一点建议
1DLL基本知识
2编写我们的DLL
3编写加载我们DLL的Loader,实现一个类似RUNDLL32.EXE的程序
4线程注入之Loader编写
5全局钩子之实现
0一点建议
书不是重头看到尾,有些书只是用来参考的..所以不要什么书都看...把基础打好,就可以
深入去探讨某些问题..不懂的就找资料..查,总结收获,这样学到的知识才是你的
这文章很多代码没怎么注释,这样文章感觉会比较长,而且很多解释MSDN和<<windows核心
编程>>讲的很好了,就不再重复.,而且讲这些东西很累比如说什么DllMain()和哪个API..
这些别人说的已经足够好了,如果不懂应该先去把基础打好.好了费话到此..
1 DLL基本知识
DLLs,函数储存在一个独立的动态链接库文件中。在创建Windows程序时,链接过程并不
把DLLs文件链接到程序上。直到程
序运行并调用一个DLLs中的函数时,该程序才要求这个函数的地址。此时Windows才在
DLLs中寻找被调用函数,并把它的地址传送给调用程序。采用这种方法,DLLs达到了复用
代码的极限。
DLLs不仅提供了函数重用的机制,而且提供了数据共享的机制。任何应用程序都可以共享
由装入内存的DLLs管理的内存资源块。只包含共享数据的DLLs称为资源文件。如Windows
的字体文件等
2 编写我们的DLL
上次在吧里已经有发一个帖说明怎么编写DLL了http://tieba.baidu.com/f?kz=304645377,,不过那是很基本的..现在我们重新再写一个吧...里面有俩个函数,一个是
修改系统时间的..,一个是输出你电脑用户名的...就是前些时候我写的哪个
好了开始我们的DLL编写,让它导出俩个函数
VC++6.0打开->文件->新建->工程->win32 动态连接库-> 工程名我写了sysnap
然后一个空的DLL工程,完成
接下来就是文件->新建->c++ source
开始写代码
#include <windows.h>
_declspec(dllexport) void SetTime()
{
WORD wYear;
SYSTEMTIME time;
printf("想改到哪年:");
scanf("%d",&wYear);
GetSystemTime(&time);
time.wYear = wYear;
if (!SetSystemTime(&time))
printf("修改错误");
}
_declspec(dllexport) void sysnap()
{
const int nBufSize = MAX_COMPUTERNAME_LENGTH + 1;
DWORD nSize = nBufSize;
char name[nBufSize];
GetComputerName(name,&nSize);
MessageBox(NULL,name,TEXT("信息"), MB_ICONINFORMATION );
}
在
好了,开始编译.得到了一个DLL,它导出了俩个函数名
?sysnap@@YAXXZ和?SetTime@@YAXXZ
下面我们要用到的名字就是这俩个,,,呵呵,是不是感觉很难记,有没有可以直接导出
sysnap这样的名字,有//...在VC编写前可以自己弄,这里我就不说(其实我再弄的时候没考
虑到导出名,呵呵..不过已经编译好了.算了)
3编写加载我们DLL的Loader,实现一个类似RUNDLL32.EXE的程序
好了,我们的DLL已经编写好了,现在就是运行它了,当然不可能双击运行,我们需要编写一
个加载这个DLL的Loader
依然是打开VC,编写控制台程序,我命名为sysnap..所以编译后得到sysnap.exe
代码如下
#include <windows.h>
#include <stdio.h>
void main()
{
typedef int (*ADDPROC)();
HINSTANCE hInst;
char funName[30];
char dllName[30];
printf("______献给黑吧______");
printf("想使用哪个DLL中的函数:/n");
scanf("%s",dllName);
hInst=LoadLibrary(dllName);
if(hInst)
{
printf("%s加载成功",dllName);
}
else
{
return;
}
printf("想使用%s中的哪个函数/n",dllName);
scanf("%s",funName);
ADDPROC HOOK=(ADDPROC)GetProcAddress(hInst,funName);
if(!HOOK)
{
printf("失败!");
return;
}
else
{ //hwnd=GetConsoleHwnd();
HOOK();
printf("成功!");
int a;
scanf("%d",&a);
}
}
编译它,得到一个EXE程序,把我们的sysnap.dll放到跟它同一个目录下,这样可以方便快速 找个我们的dll,现在可以按照我们这个程序运行我们的DLL了,依次输入sysnap.dll,? sysnap@@YAXXZ看到没,弹出一个窗口,里面显示了我们的电脑用户名..你也可以运行第二 个函数,sysnap.dll....?SetTime@@YAXXZ...因为开始没考虑到导出名字问题,所以写到这就算了...如果想导出sysnap和SetTime这样的函数名是可以的,怎么弄你自己上网查下本来还想写是弄成rundll32.exe形式的,不过没什么意义就算了,,其实也很简单...就是用main()的俩个参数argv和argc..有兴趣可以自己实现 4线程注入之Loader编写
大家知道,上面的sysnap.exe是来加载我们的DLL..那就是说如果把进程sysnap.exe关掉, 那DLL也被卸载,那有没有办法让我们的loader运行一次,然后我们的dll就一直运行而无论 sysnap.exe进程是否被关掉,有..那就是线程注入,把我们的dll注入到别的进程...接下来
我们就是来实现这样一个loader..测试的dll的代码在前几天我的章里有
http://tieba.baidu.com/f?kz=304645377这个DLL是有DLLMain()的..详细参考<<windows 核心编程>>好了...
主要思想是根据我们要注入的进程名得到它的ID,然后是提权,最后就是注入
代码如下..可以看下<<windows核心编程和MSDN>>
#include <windows.h>
#include <stdio.h>
#include <Tlhelp32.h>
BOOL InjectDll(const char *DllFullPath, const DWORD dwRemoteProcessId);
int Hightpriv(const char * name) ;
DWORD GetProcessIdByName(LPCTSTR name);
int main()
{
char strname[30];
char dllname[30];
int proID;
printf("想注入哪个进程,比如explorer.exe,请注意大小写,:");
scanf("%s",strname);
printf("想把哪个dll注入,请填好完整路劲名:");
scanf("%s",dllname);
proID=GetProcessIdByName(strname);
InjectDll(dllname,proID) ;
return 0;
}
//开始我们的工作了,<<windows核心编程里讲的比较细>>
BOOL InjectDll(const char *DllFullPath, const DWORD dwRemoteProcessId)
{
HANDLE hRemoteProcess;
Hightpriv(SE_DEBUG_NAME);
char *pszLibFileRemote;
hRemoteProcess = OpenProcess( PROCESS_ALL_ACCESS, FALSE, dwRemoteProcessId);
pszLibFileRemote = (char *) VirtualAllocEx( hRemoteProcess, NULL, lstrlen
(DllFullPath)+1, MEM_COMMIT, PAGE_READWRITE);
WriteProcessMemory(hRemoteProcess,pszLibFileRemote, (void *) DllFullPath,
lstrlen(DllFullPath)+1, NULL);
PTHREAD_START_ROUTINE pfnStartAddr = (PTHREAD_START_ROUTINE)GetProcAddress
(GetModuleHandle(TEXT("Kernel32")), "LoadLibraryA");
HANDLE hRemoteThread;
if( (hRemoteThread = CreateRemoteThread(
hRemoteProcess, NULL, 0, pfnStartAddr, pszLibFileRemote, 0, NULL) ) == NULL)
{
printf("注入线程失败!");
return FALSE;
}
CloseHandle(hRemoteProcess);
CloseHandle(hRemoteThread);
return TRUE;
}
//提高我们程序的权限,因为我们要操作的是系统中的其他进程,如果没有足够的系统权限,我们是无法写入甚至连读取其它进程的内存地址的
int Hightpriv(const char * name)
{
HANDLE hToken;
TOKEN_PRIVILEGES tp;
LUID luid;
OpenProcessToken(GetCurrentProcess(),
TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY,
&hToken);
LookupPrivilegeValue(NULL,name,&luid) ;
tp.PrivilegeCount = 1;
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
tp.Privileges[0].Luid = luid;
AdjustTokenPrivileges(hToken,0,&tp,sizeof
(TOKEN_PRIVILEGES),NULL,NULL);
return 0;
}
//主要是枚举进程名,与我们想要注入的做比较,如果是就返回它的ID,ROCESSENTRY32是一
个与进程有关的数据结构
DWORD GetProcessIdByName(LPCTSTR name)
{
PROCESSENTRY32 prostruct;
DWORD id = 0;
HANDLE hSnapshot;
hSnapshot= CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);
prostruct.dwSize = sizeof(PROCESSENTRY32);
if(!Process32First(hSnapshot,&prostruct))
return 0;
do
{
prostruct.dwSize = sizeof(PROCESSENTRY32);
if(!Process32Next(hSnapshot,&prostruct))
break;
if(strcmp(prostruct.szExeFile,name) == 0)
{
id = prostruct.th32ProcessID;
break;
}
}while(TRUE);
CloseHandle(hSnapshot);
return id;
}
编译后得到了一个EXE文件,现在我们把我们的DLL注入到notepad.exe..这个dll的代码可以在http://tieba.baidu.com/f?kz=304645377的到,自己编译一下..
好了,线程注入就这么完成