发新话题
打印

菜鸟升级一号专题(已完成)

音量为何会自动调节

  问:我用Winamp听MP3时,每听完一首歌之后,音量调节(即双击小喇叭图标)的第二个控制钮“WAVE”便从刚调节的音量处降到最下面,但在玩游戏、看VCD时没出现过此种情况,这是什么原因造成的,该如何解决?

  答:运行Winmap,打开“选项→参数设置→插件→输出”菜单,选择“WaveOut输出...”插件,点击“配置”按钮,在弹出的对话框中取消“停止时复位到原始值”(去掉前面的小钩),按“确定”按钮即可。

TOP

进行DLL注入的三种方法

在WINDOWS中,每个进程都有自己独立的地址空间,这样一个应用程序就无法进入另一个进程的地址空间而不会破坏另一个进程的运行,这样使得系统更加的稳定。但这样一来,相反的,如果我们要对我们感兴趣的进程进行操作也就变得复杂起来。比如,我们要为另一个进程创建的窗口建立子类或是要想从其中一个感兴趣的进程中取得一些有趣的信息(比如你想得到WIN2000用户登录的密码)。而DLL注入技术就是正好可以解决这些问题。DLL注入就是将DLL插入到其它你指定的进程的地址空间中,使得我们可以对感兴趣的进程进行操作。

  在我们的DLL注入到指定的进程空间时,为了可以使我们更清楚地看到它已经成功对注入到了指定的进程空间,所以我们有需要使用一个简单的工具来查看指定的进程空间中所载入的所有模块,以便确定我们的DLL是否已经成功注入。如果你系统中装有WINDOWS优化大师,那么你可以利用它提供的进程工具来查看,没有也没关系,我用BCB写了一个小工具,虽然不怎么方便,但也可以清楚地看到指定进程空间中的所有载入模块。

  该工具的主要代码如下:
//------------------------------------

void __fastcall TfrmMain::btLookClick(TObject *Sender)

{

DWORD dwProcessId;

BOOL bRet;

MODULEENTRY32 hMod = {sizeof(hMod)};

HANDLE hthSnapshot = NULL;

BOOL bMoreMods = FALSE;

ListView->Clear();

if (Edit->Text == "")

return;

else

dwProcessId = StrToInt(Edit->Text);

// 为进程建立一个快照

hthSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE,

dwProcessId);

if (hthSnapshot == NULL)

{

MessageBox(Handle,("CreateToolhelp32Snapshot failed with error "

+ IntToStr(GetLastError())).c_str(),"Error!",

MB_ICONINFORMATION + MB_OK);

return;

}

// 获取模块列表中的模块

bMoreMods = Module32First(hthSnapshot, &hMod);

if (bMoreMods == FALSE)

{

MessageBox(Handle,("Module32First failed with error "

+ IntToStr(GetLastError())).c_str(),"Error!",

MB_ICONINFORMATION + MB_OK);

return;

}

for (; bMoreMods; bMoreMods = Module32Next(hthSnapshot, &hMod))

{

TListItem *Item;

Item = ListView->Items->Add();

Item->Caption = String(hMod.szExePath);

Item->ImageIndex = 0;

}

// 关闭句柄

CloseHandle(hthSnapshot);

}

  接下来就开始我们的正题吧。

  DLL注入主要有三种方法,即应用HOOK技术、创建远程线程和特洛伊DLL三种。

  一、应用HOOK技术进行DLL注入

  我原来写过有关HOOK的介绍,如果你看过了或者是以前写过HOOK程序,那么你已经会这种DLL注入了。它其它就是为系统或某个线程安装一个钩子。这里要说的是,如果是全局钩子,那么你的DLL将会在进程调用时载入到任意一个调用的进程的地址空间中,这样是相当浪费资源的。因此我在下载的演示中就只对某一个指定的线程安装线程钩子。

  1、用BCB建立一个DLL工程(如果你用的是VC或其它,请自己对照),输入以下代码:

//=====================================

// 文件: UnitLib.cpp

// 说明: 演示利用钩子技术进行DLL注入.

// 将本DLL中的代码注入到指定的进程空间.

// 作者: 陶冶(无邪)

//=========================================

// 函数声明

extern "C" __declspec(dllexport) __stdcall

bool SetHook(DWORD dwThreadId);

extern "C" __declspec(dllexport) __stdcall

LRESULT CALLBACK MyProc(int nCode, WPARAM wParam, LPARAM lParam);

static HHOOK hHook = NULL; // 钩子句柄

static HINSTANCE hInst; // 当前DLL句柄

int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void* lpReserved)

{

hInst = hinst;

return 1;

}

//---------------------------------------

// 安装钩子函数

bool __declspec(dllexport) __stdcall SetHook(DWORD dwThreadId)

{

if (dwThreadId != 0)

{

MessageBox(NULL, ("DLL已经注入!\nThreadId = " +

IntToStr(dwThreadId)).c_str(),"DLL",

MB_ICONINFORMATION + MB_OK);

    // 安装指定线程的钩子

hHook = SetWindowsHookEx(WH_GETMESSAGE, (HOOKPROC)MyProc,

hInst,dwThreadId);

if (hHook != NULL)

return true;

}else

{

MessageBox(NULL, "DLL即将从记事本进程空间中撤出!","DLL",

MB_ICONINFORMATION + MB_OK);

return (UnhookWindowsHookEx(hHook));

}

return true;

}

// 钩子函数

LRESULT CALLBACK __declspec(dllexport) __stdcall

MyProc(int nCode, WPARAM wParam, LPARAM lParam)

{

  // 因为只是演示DLL注入,所以这里什么也不做,交给系统处理

return (CallNextHookEx(hHook, nCode, wParam, lParam));

}

//---------------------------------------------

该DLL中有两个函数,一个为安装钩子函数(SetHook),另一个为钩子函数(MyProc)。其中安装钩子函数提供了一个参数,由该参数指定安装到哪个线程,如果该参数为0,则卸载钩子。

  编译该工程,即生成我们要用来注入到指定进程中的DLL文件了。

2、建立测试工程。用BCB建立一个应用程序工程,在窗体中添加两个按钮,一个用来安装线程钩子,一个用来卸载。代码如下:

//-------------------------------------

// SetHook函数原型声明

typedef BOOL (WINAPI *LPSETHOOK)(unsigned long dwThreadId);

//------------------------------------------

__fastcall TfrmMain::TfrmMain(TComponent* Owner)

: TForm(Owner)

{

}

//--------------------------------------

// 安装钩子

void __fastcall TfrmMain::Button1Click(TObject *Sender)

{

String szPath;

LPSETHOOK lproc;

HANDLE hDll;

BOOL bRet;

PROCESS_INFORMATION info;

STARTUPINFO start;

memset(&start, 0, sizeof(start));

// 取得要载入的DLL文件名

szPath = Application->ExeName;

szPath = szPath.SubString(0, szPath.Length()

- String(StrRScan(szPath.c_str(),'\\')).Length());

szPath = szPath + "\\DllLib.dll";

  // 载入DLL

hDll = LoadLibrary(szPath.c_str());

if (hDll != NULL)

{

lproc = (LPSETHOOK)GetProcAddress(hDll,"SetHook");

if (lproc != NULL)

{

// 因为没有适当的工具可以取得线程ID,也为了简单起见,所以这里新创建了一个记事本进程,以便取得它的线程ID,对其安装钩子,把我们的DLL注入到记事本进程中。

bRet = CreateProcess(NULL,

"c:\\winnt\\system32\\notepad.exe",

NULL,

NULL,

TRUE,

0,

NULL,

NULL,

&start,

&info);

if (bRet != 0)

{

if((*lproc)(info.dwThreadId) == false)

ShowMessage("Sethook failed with error " +

IntToStr(GetLastError()));

}

else

{

ShowMessage("CreateProcess failed with error " +

IntToStr(GetLastError()));

}

}

}

}

//--------------------------------------

// 卸载钩子

void __fastcall TfrmMain::Button2Click(TObject *Sender)

{

String szPath;

LPSETHOOK lproc;

HANDLE hDll;

szPath = Application->ExeName;

szPath = szPath.SubString(0, szPath.Length()

- String(StrRScan(szPath.c_str(),'\\')).Length());

szPath = szPath + "\\DllLib.dll";

hDll = LoadLibrary(szPath.c_str());

if (hDll != NULL)

{

lproc = (LPSETHOOK)GetProcAddress(hDll,"SetHook");

if (lproc != NULL)

(*lproc)(0);

}

}

//-----------------------------------------

  接下来生成可执行文件,点击第一个安装钩子按钮,然后你就可以用我们最开始写的查看模块的工具来查看了,你将会在模块中看到你刚才DLL的路径及文件名,这表明我们已经成功地将自己的DLL注入到了记事本进程空间。点击卸载按钮后,再查看记事本进程中的模块,将不会看到我们DLL文件的完整文件名,这表明已经成功撤消了对记事本进程的注入。

  二、利用远程线程来进行DLL注入

    这种方法同前一种方法相比,要显得复杂一些,并且这种方法只能在WIN2000中使用(XP,和最新的2003不知道)。具体步骤如下:

  1)、取得远程进程的进程ID;

  2)、在远程进程空间中分配一段内存用来存放要注入的DLL完整路径;

  3)、将要注入的DLL的路径写到刚才分配的远程进程空间;

  4)、从Kernel32.dll中取得LoadLibray的地址;

  5)、调用CreateRemoteThread函数以从Kernel32.dll中取得的LoadLibrary函数的地址为线程函数的地址,以我们要注入的DLL文件名为参数,创建远程线程;

  在第二三步中,为什么要把我们要注入的DLL的文件名写到远程进程的地址空间进行操作,《WINDOWS核心编程》中是这样描述的:

“(要注入的DLL文件名)字符串是在调用进程的地址空间中。该字符串的地址已经被赋予新创建的远程线程,该线程将它传递给L o a d L i b r a r y A。但是,当L o a d L i b r a r y A取消对内存地址的引用时, D L L路径名字符串将不再存在,远程进程的线程就可能引发访问违规”;

  至于第四步中为什么不直接对LoadLibrary进行调用,《WINDOWS核心编程》中是这样描述的:

“如果在对C r e a t e R e m o t e T h r e a d的调用中使用一个对L o a d L i b r a r y A的直接引用,这将在你的模块的输入节中转换成L o a d L i b r a r y A的形实替换程序的地址。将形实替换程序的地址作为远程线程的起始地址来传递,会导致远程线程开始执行一些令人莫名其妙的东西。其结果很可能造成访问违规。”

好了,下面开始我们的例子。

  1、同上面应用HOOK来进行DLL注入一样,我们先创建一个DLL工程,这个DLL完全可以不编写任何代码,因为我们只想将DLL注入到指定进程就达到目的了,但为了好看,我还是随便在其中写一个API函数。代码如下:

extern "C" __declspec(dllexport) __stdcall void About();

int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void* lpReserved)

{

return 1;

}

//-----------------------------------------------

void __declspec(dllexport) __stdcall About()

{

MessageBox(NULL,"这个DLL模块演示了DLL的注入技术。\n"

"通过程序的调用LoadLibrary将本模块注入到指定的"

"进程的地址空间中。", "DLL注入技术",

MB_ICONINFORMATION + MB_OK);

}

  编译它,就得到我们用来注入的DLL文件了。接下来是测试工程。

  2、编写测试工程。用BCB建立一个应用程序工程,在窗体中放入两个按钮,一个用来注入,一个用来撤消,另外还有一个文本框控件,用来等待用户输入进程ID号。代码如下:

//-------------------------------------------

// DLL注入函数

BOOL WINAPI LoadLib(DWORD dwProcessId, LPWSTR lpszLibName)

{

HANDLE hProcess = NULL,

hThread = NULL;

LPWSTR lpszRemoteFile = NULL;

// 打开远程进程

hProcess = OpenProcess(PROCESS_CREATE_THREAD

| PROCESS_VM_OPERATION

| PROCESS_VM_WRITE,

FALSE,

dwProcessId);

if (hProcess == NULL)

{

MessageBox(NULL, ("OpenProcess failed with error "

+ IntToStr(GetLastError())).c_str(), "Error",

MB_ICONINFORMATION + MB_OK);

return FALSE;

}

// 在远程进程中分配存贮DLL文件名的空间

lpszRemoteFile = (LPWSTR)VirtualAllocEx(hProcess, NULL,

sizeof(WCHAR) * lstrlenW(lpszLibName) + 1,

MEM_COMMIT, PAGE_READWRITE);

if (lpszRemoteFile == NULL)

{

MessageBox(NULL, ("VirtualAllocEx failed with error "

+ IntToStr(GetLastError())).c_str(), "Error",

MB_ICONINFORMATION + MB_OK);

return FALSE;

}

// 复制DLL文件名到远程刚分配的进程空间

if (!WriteProcessMemory(hProcess, lpszRemoteFile,

(PVOID)lpszLibName, sizeof(WCHAR) * lstrlenW(lpszLibName) + 1,

NULL))

{

MessageBox(NULL, ("WriteProcessMemory failed with error "

+ IntToStr(GetLastError())).c_str(), "Error",

MB_ICONINFORMATION + MB_OK);

return FALSE;

}

// 取得LoadLibrary函数在Kennel32.dll中的地址

PTHREAD_START_ROUTINE pfnThreadRtn =

(PTHREAD_START_ROUTINE)GetProcAddress(

GetModuleHandle("Kernel32.dll"),"LoadLibraryW");

if (pfnThreadRtn == NULL)

{

MessageBox(NULL, ("GetProcAddress failed with error "

+ IntToStr(GetLastError())).c_str(), "Error",

MB_ICONINFORMATION + MB_OK);

return FALSE;

}

// 创建远程线程

hThread = CreateRemoteThread(hProcess,

NULL,

0,

pfnThreadRtn, // LoadLibrary地址

lpszRemoteFile, // 要加载的DLL名

0,

NULL);

if (hThread == NULL)

{

MessageBox(NULL, ("CreateRemoteThread failed with error "

+ IntToStr(GetLastError())).c_str(), "Error",

MB_ICONINFORMATION + MB_OK);

return FALSE;

}

// 等待线程返回

WaitForSingleObject(hThread, INFINITE);

// 释放进程空间中的内存

VirtualFreeEx(hProcess, lpszRemoteFile, 0, MEM_RELEASE);

// 关闭句柄

CloseHandle(hThread);

CloseHandle(hProcess);

return TRUE;

}

// 在进程空间释放注入的DLL

BOOL WINAPI FreeLib(DWORD dwProcessId, LPTSTR lpszLibName)

{

HANDLE hProcess = NULL,

hThread = NULL,

hthSnapshot = NULL;

MODULEENTRY32 hMod = {sizeof(hMod)};

BOOL bFound;

// 取得指定进程的所有模块映象

hthSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE,

dwProcessId);

if (hthSnapshot == NULL)

{

MessageBox(NULL, ("CreateRemoteThread failed with error "

+ IntToStr(GetLastError())).c_str(), "Error",

MB_ICONINFORMATION + MB_OK);

return FALSE;

}

// 取得所有模块列表中的指定的模块

BOOL bMoreMods = Module32First(hthSnapshot, &hMod);

if (bMoreMods == FALSE)

{

MessageBox(NULL, ("Module32First failed with error "

+ IntToStr(GetLastError())).c_str(), "Error",

MB_ICONINFORMATION + MB_OK);

return FALSE;

}

// 循环取得想要的模块

for (;bMoreMods; bMoreMods = Module32Next(hthSnapshot, &hMod))

{

//ShowMessage(String(hMod.szExePath) + " | " + String(lpszLibName));

if ((strcmp(hMod.szExePath, lpszLibName) == 0) ||

(strcmp(hMod.szModule, lpszLibName) == 0))

break;

}

// 打开进程

hProcess = OpenProcess(PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION,

FALSE, dwProcessId);

if (hProcess == NULL)

{

MessageBox(NULL, ("OpenProcess failed with error "

+ IntToStr(GetLastError())).c_str(), "Error",

MB_ICONINFORMATION + MB_OK);

return FALSE;

}

// 取得FreeLibrary函数在Kernel32.dll中的地址

PTHREAD_START_ROUTINE pfnThreadRtn =

(PTHREAD_START_ROUTINE)GetProcAddress(

GetModuleHandle("Kernel32.dll"), "FreeLibrary");

if (pfnThreadRtn == NULL)

{

MessageBox(NULL, ("GetProcAddress failed with error "

+ IntToStr(GetLastError())).c_str(), "Error",

MB_ICONINFORMATION + MB_OK);

return FALSE;

}

// 创建远程线程来执行FreeLibrary函数

hThread = CreateRemoteThread(hProcess,

NULL,

0,

pfnThreadRtn,

hMod.modBaseAddr,

0,

NULL);

if (hThread == NULL)

{

MessageBox(NULL, ("CreateRemoteThread failed with error "

+ IntToStr(GetLastError())).c_str(), "Error",

MB_ICONINFORMATION + MB_OK);

return FALSE;

}

// 等待线程返回

WaitForSingleObject(hThread, INFINITE);

// 关闭句柄

CloseHandle(hThread);

CloseHandle(hthSnapshot);

CloseHandle(hProcess);

return TRUE;

}

//---------------------------

void __fastcall TfrmMain::btLoadClick(TObject *Sender)

{

m_szDllFile = Application->ExeName;

m_szDllFile = m_szDllFile.SubString(0, m_szDllFile.Length()

- String(StrRScan(m_szDllFile.c_str(),'\\')).Length());

m_szDllFile = m_szDllFile + "\\DllLib.dll";

m_dwProcessId = StrToInt(Edit->Text);

LoadLib(m_dwProcessId, WideString(m_szDllFile).c_bstr());

}

//-------------------------------------------

void __fastcall TfrmMain::btUnloadClick(TObject *Sender)

{

FreeLib(m_dwProcessId, m_szDllFile.c_str());

}

//--------------------------------------

好了,把上面的工程编译成生EXE文件,接下来我们就可以进行DLL的注入测试了。先打开记事本(当然你也可以打开其它的进程,或直接在已经加载的进程测试),通过WINDOWS的任务管理器,找到它的进程ID。然后运行我们的测试工程,在文本框中输入进程ID,点击注入。这时我们就可以通过我们最先写的小工具来查看它的进程空间中所包含的模块了,你会发现,我们的DLL已经成功加载到了它的进程空间中。点击卸载,取消DLL的注入。

三、利用特洛伊DLL进行注入

这种方法的原理就是由自己写一个与原有进程调用的DLL具有相同接口函数的DLL,再用我们的DLL替换原有的DLL。在替换的过程中,由我们自己编写感兴趣的函数替换原有函数,而对其它不感兴趣的函数,则以函数转发的形式调用原有DLL中的函数。这里面有个前提,就是你在编写DLL时你必须知道原有DLL中的函数都有哪些,以免导至其它进程调用DLL时找不到相应的API函数,特别是在替换系统DLL文件时更要小心。

下面就来演示一下这种方式。我是这样做的,首先写一个DLL作为被替换的DLL,名为DllLib.dll(最后更名为_DllLib.dll),然后写特洛伊DLL,名为TroyDll.Dll(最后更名为原有DLL名,即DllLib.dll),与DllLib.Dll具有相同的API函数过程,但是对其中的一个API函数做更改,使其完成我们的工作,因为另外还有一个API函数需要对其进行函数转发,转给原来的DLL,即(更名为_DllLib.dll的DllLib.dll)。这时我们的测试程序本来是调用的DllLib.dll的,但由于DllLib.dll已经被TroyDll.dll替换了,所以测试程序实际上调用的是TroyDll.dll,而对于做转发的函数,则是通过TroyDll.Dll调用DllLib.dll(更名后的_DllLib.dll)完成的。此时我们的特洛伊DLL实际上已经注入到我们的测试程序的进程空间中来了。

1、编写本来的DLL。DllLib.dll(更名后为_DllLib.dll)的代码如下:

//===========================================

// 文件: UnitLib.cpp

// 说明: 演示用特洛伊DLL进行DLL注入.这个是本身的DLL,另一个特洛伊DLL将

// 对它进行函数转发,并实现另外的功能.

// 作者: 陶冶(无邪)

//===================================================

// 函数声明

extern "C" __declspec(dllexport) __stdcall void About();

extern "C" __declspec(dllexport) __stdcall int Add(int a, int b);

int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void* lpReserved)

{

return 1;

}

//---------------------------------------------------

void __declspec(dllexport) __stdcall About()

{

try

{

MessageBox(NULL,"这是本来的DLL文件!","原来的DLL",

MB_ICONINFORMATION + MB_OK);

}catch(Exception &e)

{

MessageBox(NULL,e.Message.c_str(),"DllLib",MB_OK);

}

}

// 两数相加(注意:这里是两数相加)

int __declspec(dllexport) __stdcall Add(int a, int b)

{

return (a + b);

}

2、编写特洛伊DLL。TroyDll.dll的代码如下:

//=================================================

// 文件: UnitTroy.cpp

// 说明: 这个是特洛伊DLL,呆会将它的DLL文件更改为要替换的DLL文件名

// 作者: 陶冶

//================================================

extern "C" __declspec(dllexport) __stdcall void About();

extern "C" __declspec(dllexport) __stdcall int Add(int a, int b);

int Multiply(int a, int b);

// DLL中的函数原形声明

typedef void (WINAPI *ABOUT)();

typedef int (WINAPI *ADD)(int a, int b);

static String szDllName;

int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void* lpReserved)

{

szDllName = Application->ExeName;

szDllName = szDllName.SubString(0,szDllName.Length()

- String(StrRScan(szDllName.c_str(),'\\')).Length());

// 更名后的DllLib.dll文件名

szDllName = szDllName + "\\_DllLib.dll";

return 1;

}

//----------------------------------------------

void __declspec(dllexport) __stdcall About()

{

// 直接做函数转发

HANDLE hDll = NULL;

hDll = LoadLibrary(szDllName.c_str());

ABOUT about;

try

{

if (hDll != NULL)

{

about = (ABOUT)GetProcAddress(hDll,"About");

if (about != NULL)

about();

}

else

MessageBox(NULL,"载入原来的DLL错误!", "特洛伊DLL",

MB_ICONINFORMATION + MB_OK);

}catch(Exception &e)

{

MessageBox(NULL,e.Message.c_str(),"DllTroy",MB_OK);

}

}

int __declspec(dllexport) __stdcall Add(int a, int b)

{

int nRet;

HANDLE hDll = NULL;

ADD add;

hDll = LoadLibrary(szDllName.c_str());

if (hDll != NULL)

{

// 为了方便演示,这里再做一次函数转发,以便看到本来应该返回的值。

add = (ADD)GetProcAddress(hDll,"Add");

if (add != NULL)

nRet = add(a, b);

ShowMessage("这是本来DLL中的调用结果:" + IntToStr(nRet));

}

else

MessageBox(NULL, "载入本来的DLL错误!", "特洛伊DLL", MB_OK);

// 将原来完成两数相加的更改为两数相乘,返回两数的积。

nRet = Multiply(a, b);

return nRet;

}

int Multiply(int a, int b)

{

return (a * b);

}

3、编写测试工程。在窗体中添加两个按钮,分别调用DllLib.dll中的两个API函数。代码如下:

typedef (WINAPI *ABOUT)();

typedef int (WINAPI *ADD)(int a, int b);



//---------------------------------------

__fastcall TfrmMain::TfrmMain(TComponent* Owner)

: TForm(Owner)

{

}

//--------------------------------------------

void __fastcall TfrmMain::FormCreate(TObject *Sender)

{

m_szDllName = Application->ExeName;

m_szDllName = m_szDllName.SubString(0,m_szDllName.Length()

- String(StrRScan(m_szDllName.c_str(),'\\')).Length());

m_szDllName = m_szDllName + "\\DllLib.dll";

}

//------------------------------------------------

// 调用About()函数

void __fastcall TfrmMain::Button1Click(TObject *Sender)

{

HANDLE hDll;

ABOUT about;

try

{

hDll = LoadLibrary(m_szDllName.c_str());

if (hDll != NULL)

{

about = (ABOUT)GetProcAddress(hDll,"About");

if (about != NULL)

about();

}

}catch(Exception &e)

{

MessageBox(Handle, e.Message.c_str(), "ERROR",MB_OK);

}

}

//---------------------------------------------------------------------------

// 调用Add()函数

void __fastcall TfrmMain::Button2Click(TObject *Sender)

{

HANDLE hDll;

ADD add;

int nRet;



hDll = LoadLibrary(m_szDllName.c_str());

if (hDll != NULL)

{

add = (ADD)GetProcAddress(hDll,"Add");

if (add != NULL)

nRet = add(10, 2);

ShowMessage("从特洛伊DLL中返回的结果 : " + IntToStr(nRet));

}

}

4、测试。将DllLib.dll更名为_DllLib.dll,将TroyDll.dll更名为DllLib.dll,即完成了DLL的替换。下面运行我们的测试工程,单击调用About()函数的按钮,因为About()是通过DllLib.dll(即TroyDll.dll)做的函数转发(转以给原DLL,即_DllLib.dll),所以看到的是原DLL(即_DllLib.dll)中弹出的信息框。此时用查看进程模块的工具来查看进程空间,你会发现,你的特洛伊DLL(更名后的DllLib.dll)已经成功以注入到了测试程序的进程空间中了。

单击调用Add()函数的按钮,你会看到本来是完成两数相加的,返回的结果却是两数的积,因为我们已经在特洛伊DLL中对它做了手脚。这下是利用它的关键了。WINDOWS登录时的GINA,知道吧,想得到别人登录的密码吗?那么就是用这种方法了,把MSGINA.dll这个东西给它替换成自己的DLL,再复杂的密码也照样得到啊,一点也不费精神,呵呵~。(想自己写吗?看看《WinLogon登录管理和GINA简介》吧)

环境:

WIN2000 Server + BCB 6.0

附:本文相关程序代码

参考:《WINDOWS核心编程》
写了很久了,没来得及发出来~~~~呵呵~~~~,有不对之处,欢迎大家指正~~
谢谢~~

嘿嘿~~~,开个张~

TOP

禁止ipc$默认共享的方法

以下四种方法可以参考一下:
A、一种办法是把ipc$和默认共享都删除了。但重起后还会有。这就需要改注册表。
1,先把已有的删除
net share ipc$ /del
net share admin$ /del
net share c$ /del
…………(有几个删几个)
2,禁止建立空连接
?? ?? 首先运行regedit,找到如下主键[HKEY_LOCAL_MACHINESYSTEMCurrentControlSetControlLSA]

把RestrictAnonymous(DWORD)的键值改为:00000001。
?? ? 3,禁止自动打开默认共享
?? ??

对于server版,找到如下主键[HKEY_LOCAL_MACHINESYSTEMCurrentControlSetServicesLanmanServerPara

meters]把AutoShareServer(DWORD)的键值改为:00000000。
对于pro版,则是[HKEY_LOCAL_MACHINESYSTEMCurrentControlSetServicesLanmanServerParameters]把Au

toShareWks(DWORD)的键值改为:00000000。
B、另一种是关闭ipc$和默认共享依赖的服务(不推荐)
net stop lanmanserver
可能会有提示说,XXX服务也会关闭是否继续。因为还有些次要的服务依赖于lanmanserver。一般情况按y继续就可以了。
C、最简单的办法是设置复杂密码,防止通过ipc$穷举密码。但如果你有其他漏洞,ipc$将为进一步入侵提供方便。
D、还有一个办法就是装防火墙,或者端口过滤。

TOP

禁止Win2000启动时读软驱

Windows2000不仅运行在所有的台式机上,而且适用于笔记本等移动用户。 对于笔记本电脑,软驱是它们的“可移动”(removable)设备。考虑到这一点,Win2000在启动时读软驱是为了检测机器的硬件配置情况, 并不是机器“中毒”或设计缺陷。   
    在Windows2000下,右击“我的电脑”-“属性”-“硬件”-“设备管理器”, 找到软盘驱动器,在它的“属性”对话框中设置为“禁用”就可以了。

TOP

禁止winxp的默认硬盘共享

编辑一个注册表文件,下面是内容:
Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\lanmanserver\parameters]
"autosharewks"=dword:00000000

然后保存为*.reg,执行后就可以取消win2000和winxp的默认硬盘共享了。

如果系统是服务器版本,文件内容如下:
Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\lanmanserver\parameters]
"AutoShareServer"=dword:00000000

在注册表里的HKEY_LOCAL_MACHINE/System/CurrentControlSet/Services/Lanmanserver/Parameters/修改或添加:AutoShareServer,双字节值为0,就可以关掉盘符共享了。同时,若修改或添加AutoShareWks,双字节值为0,就可以关掉Admin共享了。


win2000也是这样设置


如何判断XP是否已激活


1、开始→运行,在弹出的对话框中输入:oobe/msoobe /a,回车后系统会弹出窗口告诉你系统是 否已经激活。

2、开始->所有程序->附件->系统工具->WINDOWS激活,如果是这样的话,就恭喜你了,已经激活。你不信,可以点最后那个“WINDOWS激活”看一下就明白了。

如果是破解/没有激活,在“开始”->“所有程序”顶上就看见“WINDOWS激活”了!激活后,此项就隐藏起来了。


查看激活用了哪个CD-KEY?!

激活后才想起不知道是哪一个CD-KEY激活了XP,这时你只需运行附件中的“WinXP安装CD-Key的查看小工具.exe”即可查看!

TOP

禁止WinXP文件夹自动展开

  WinXP的资源管理器里增加了一个比较人性化的功能,就是点击左侧的文件夹(或控制面板等),如果该文件夹有子文件夹,它会自动展开此文件夹。一些用惯了老系统操作方式的用户,会嫌展开后滚动条加长,需要每次去点击展开后的“-”号。通过修改注册表即可以禁止这个功能。

  在注册表左侧展开主键[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced],把右窗口的名为“FriendlyTree”的DWORD值修改为“0”即可。返回资源管理器,点击一父目录,可以看到修改已经生效了。该主键下另一个名为“PersistBrowsers”的DWORD值是保存上次关机设置的开关状态,“1”为开,“0”为关。

TOP

禁止光盘自动运行

Win 98:
??依次打开“开始→设置→控制面板→系统→设备管理”,点击“CD-ROM”,选择光驱的型号,然后选择“属性→设置”,将“自动插入通告”前的钩取消,最后点“确定”并重新启动计算机即可。

Win 2000:
??与Win 98不同,在Win 2000中,禁止光盘自动运行需要通过修改注册表来实现:在“运行”中输入“regedit”,打开“注册表编辑器”,选择“HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Cdrom”,将“Autorun”项的值改为0即可。在Win 2000下禁用自动播放功能的方法是:在“运行”中输入“gpedit.msc”,打开“组策略编辑器”,依次点击“本地计算机策略→计算机配制→管理模板→系统”,双击右方策略窗口中的“停用自动播放”,在打开的窗口中选择“启用”复选框,并且在“停用自动播放”下拉菜单中选择“CD-ROM 驱动器”,确定后重新启动计算机即可。

Win XP:
??在Win XP里进行禁用操作比较方便。右键单击“我的电脑”里的光盘图标,选择“属性”,在弹出的窗体中选择“自动播放”选项卡,在这里用户可以针对“音乐文件”、“图片”、“视频文件”、“混合内容”和“音乐CD”五类内容设置不同的操作方式,都选用“不执行操作”即可禁用自动运行功能,“确定”后设置立即生效。

TOP

精妙SQL语句

明:复制表(只复制结构,源表名:a 新表名:b)
SQL: select * into b from a where 1<>1

说明:拷贝表(拷贝数据,源表名:a 目标表名:b)
SQL: insert into b(a, b, c) select d,e,f from b;

说明:显示文章、提交人和最后回复时间
SQL: select a.title,a.username,b.adddate from table a,(select max(adddate) adddate from table where table.title=a.title) b

说明:外连接查询(表名1:a 表名2:b)
SQL: select a.a, a.b, a.c, b.c, b.d, b.f from a LEFT OUT JOIN b ON a.a = b.c

说明:日程安排提前五分钟提醒
SQL: select * from 日程安排 where datediff(<|>minute<|>,f开始时间,getdate())>5


说明:两张关联表,删除主表中已经在副表中没有的信息
SQL:
delete from info where not exists ( select * from infobz where info.infid=infobz.infid )

说明:--
SQL:
SELECT A.NUM, A.NAME, B.UPD_DATE, B.PREV_UPD_DATE
FROM TABLE1,
(SELECT X.NUM, X.UPD_DATE, Y.UPD_DATE PREV_UPD_DATE
FROM (SELECT NUM, UPD_DATE, INBOUND_QTY, STOCK_ONHAND
FROM TABLE2
WHERE TO_CHAR(UPD_DATE,<|>YYYY/MM<|>) = TO_CHAR(SYSDATE, <|>YYYY/MM<|>)) X,
(SELECT NUM, UPD_DATE, STOCK_ONHAND
FROM TABLE2
WHERE TO_CHAR(UPD_DATE,<|>YYYY/MM<|>) =
TO_CHAR(TO_DATE(TO_CHAR(SYSDATE, <|>YYYY/MM<|>) || <|>/01<|>,<|>YYYY/MM/DD<|>) - 1, <|>YYYY/MM<|>) ) Y,
WHERE X.NUM = Y.NUM (+)
AND X.INBOUND_QTY + NVL(Y.STOCK_ONHAND,0) <> X.STOCK_ONHAND ) B
WHERE A.NUM = B.NUM

说明:--
SQL:
select * from studentinfo where not exists(select * from student where studentinfo.id=student.id) and 系名称=<|>"&strdepartmentname&"<|> and 专业名称=<|>"&strprofessionname&"<|> order by 性别,生源地,高考总成绩

说明:
从数据库中去一年的各单位电话费统计(电话费定额贺电化肥清单两个表来源)
SQL:
SELECT a.userper, a.tel, a.standfee, TO_CHAR(a.telfeedate, <|>yyyy<|>) AS telyear,
SUM(decode(TO_CHAR(a.telfeedate, <|>mm<|>), <|>01<|>, a.factration)) AS JAN,
SUM(decode(TO_CHAR(a.telfeedate, <|>mm<|>), <|>02<|>, a.factration)) AS FRI,
SUM(decode(TO_CHAR(a.telfeedate, <|>mm<|>), <|>03<|>, a.factration)) AS MAR,
SUM(decode(TO_CHAR(a.telfeedate, <|>mm<|>), <|>04<|>, a.factration)) AS APR,
SUM(decode(TO_CHAR(a.telfeedate, <|>mm<|>), <|>05<|>, a.factration)) AS MAY,
SUM(decode(TO_CHAR(a.telfeedate, <|>mm<|>), <|>06<|>, a.factration)) AS JUE,
SUM(decode(TO_CHAR(a.telfeedate, <|>mm<|>), <|>07<|>, a.factration)) AS JUL,
SUM(decode(TO_CHAR(a.telfeedate, <|>mm<|>), <|>08<|>, a.factration)) AS AGU,
SUM(decode(TO_CHAR(a.telfeedate, <|>mm<|>), <|>09<|>, a.factration)) AS SEP,
SUM(decode(TO_CHAR(a.telfeedate, <|>mm<|>), <|>10<|>, a.factration)) AS OCT,
SUM(decode(TO_CHAR(a.telfeedate, <|>mm<|>), <|>11<|>, a.factration)) AS NOV,
SUM(decode(TO_CHAR(a.telfeedate, <|>mm<|>), <|>12<|>, a.factration)) AS DEC
FROM (SELECT a.userper, a.tel, a.standfee, b.telfeedate, b.factration
FROM TELFEESTAND a, TELFEE b
WHERE a.tel = b.telfax) a
GROUP BY a.userper, a.tel, a.standfee, TO_CHAR(a.telfeedate, <|>yyyy<|>)

说明:四表联查问题:
SQL: select * from a left inner join b on a.a=b.b right inner join c on a.a=c.c inner join d on a.a=d.d where .....

说明:得到表中最小的未使用的ID号
SQL:
SELECT (CASE WHEN EXISTS(SELECT * FROM Handle b WHERE b.HandleID = 1) THEN MIN(HandleID) + 1 ELSE 1 END) as HandleID
FROM Handle
WHERE NOT HandleID IN (SELECT a.HandleID - 1 FROM Handle a)

TOP

开始→运行→命令集锦

gpedit.msc-----组策略 sndrec32-------录音机
Nslookup-------IP地址侦测器 explorer-------打开资源管理器
logoff---------注销命令 tsshutdn-------60秒倒计时关机命令
lusrmgr.msc----本机用户和组 services.msc---本地服务设置
oobe/msoobe /a----检查XP是否激活 notepad--------打开记事本
cleanmgr-------垃圾整理 net start messenger----开始信使服务
compmgmt.msc---计算机管理 net stop messenger-----停止信使服务
conf-----------启动netmeeting dvdplay--------DVD播放器
charmap--------启动字符映射表 diskmgmt.msc---磁盘管理实用程序
calc-----------启动计算器 dfrg.msc-------磁盘碎片整理程序
chkdsk.exe-----Chkdsk磁盘检查 devmgmt.msc--- 设备管理器
regsvr32 /u *.dll----停止dll文件运行 drwtsn32------ 系统医生
rononce -p ----15秒关机 dxdiag---------检查DirectX信息
regedt32-------注册表编辑器 Msconfig.exe---系统配置实用程序
rsop.msc-------组策略结果集 mem.exe--------显示内存使用情况
regedit.exe----注册表 winchat--------XP自带局域网聊天
progman--------程序管理器 winmsd---------系统信息
perfmon.msc----计算机性能监测程序 winver---------检查Windows版本
sfc /scannow-----扫描错误并复原
taskmgr-----任务管理器(2000/xp/2003)

TOP

控制面板大全

  在程序运行过程中启动控制面板的各个设置功能:
var x:cardinal;
begin
{启动控制面板}
x:=winexec('rundll32.exe shell32.dll,Control_RunDLL',9);
{辅助选项 属性-键盘}
x:=winexec('rundll32.exe shell32.dll,Control_RunDLL access.cpl,,1',9);
{辅助选项 属性-声音}
x:=winexec('rundll32.exe shell32.dll,Control_RunDLL access.cpl,,2',9);
{辅助选项 属性-显示}
x:=winexec('rundll32.exe shell32.dll,Control_RunDLL access.cpl,,3',9);
{辅助选项 属性-鼠标}
x:=winexec('rundll32.exe shell32.dll,Control_RunDLL access.cpl,,4',9);
{辅助选项 属性-常规}
x:=winexec('rundll32.exe shell32.dll,Control_RunDLL access.cpl,,5',9);
{添加/删除程序 属性-安装/卸载}
x:=winexec('rundll32.exe shell32.dll,Control_RunDLL Appwiz.cpl,,1',9);
{添加/删除程序 属性-Windows安装程序}
x:=winexec('rundll32.exe shell32.dll,Control_RunDLL Appwiz.cpl,,2',9);
{添加/删除程序 属性-启动盘}
x:=winexec('rundll32.exe shell32.dll,Control_RunDLL Appwiz.cpl,,3',9);
{显示 属性-背景}
x:=winexec('rundll32.exe shell32.dll,Control_RunDLL desk.cpl,,0',9);
{显示 属性-屏幕保护程序}
x:=winexec('rundll32.exe shell32.dll,Control_RunDLL desk.cpl,,1',9);
{显示 属性-外观}
x:=winexec('rundll32.exe shell32.dll,Control_RunDLL desk.cpl,,2',9);
{显示 属性-设置}
x:=winexec('rundll32.exe shell32.dll,Control_RunDLL desk.cpl,,3',9);
{Internet 属性-常规}
x:=winexec('rundll32.exe shell32.dll,Control_RunDLL Inetcpl.cpl,,0',9);
{Internet 属性-安全}
x:=winexec('rundll32.exe shell32.dll,Control_RunDLL Inetcpl.cpl,,1',9);
{Internet 属性-内容}
x:=winexec('rundll32.exe shell32.dll,Control_RunDLL Inetcpl.cpl,,2',9);
{Internet 属性-连接}
x:=winexec('rundll32.exe shell32.dll,Control_RunDLL Inetcpl.cpl,,3',9);
{Internet 属性-程序}
x:=winexec('rundll32.exe shell32.dll,Control_RunDLL Inetcpl.cpl,,4',9);
{Internet 属性-高级}
x:=winexec('rundll32.exe shell32.dll,Control_RunDLL Inetcpl.cpl,,5',9);
{区域设置 属性-区域设置}
x:=winexec('rundll32.exe shell32.dll,Control_RunDLL Intl.cpl,,0',9);
{区域设置 属性-数字}
x:=winexec('rundll32.exe shell32.dll,Control_RunDLL Intl.cpl,,1',9);
{区域设置 属性-货币}
x:=winexec('rundll32.exe shell32.dll,Control_RunDLL Intl.cpl,,2',9);
{区域设置 属性-时间}
x:=winexec('rundll32.exe shell32.dll,Control_RunDLL Intl.cpl,,3',9);
{区域设置 属性-日期}
x:=winexec('rundll32.exe shell32.dll,Control_RunDLL Intl.cpl,,4',9);
{游戏控制器-一般}
x:=winexec('rundll32.exe shell32.dll,Control_RunDLL Joy.cpl,,0',9);
{游戏控制器-高级}
x:=winexec('rundll32.exe shell32.dll,Control_RunDLL Joy.cpl,,1',9);
{鼠标 属性}
x:=winexec('rundll32.exe shell32.dll,Control_RunDLL Main.cpl',9);
{多媒体 属性-音频}
x:=winexec('rundll32.exe shell32.dll,Control_RunDLL Mmsys.cpl,,0',9);
{多媒体 属性-视频}
x:=winexec('rundll32.exe shell32.dll,Control_RunDLL Mmsys.cpl,,1',9);
{多媒体 属性-MIDI}
x:=winexec('rundll32.exe shell32.dll,Control_RunDLL Mmsys.cpl,,2',9);
{多媒体 属性-CD音乐}
x:=winexec('rundll32.exe shell32.dll,Control_RunDLL Mmsys.cpl,,3',9);
{多媒体 属性-设备}
x:=winexec('rundll32.exe shell32.dll,Control_RunDLL Mmsys.cpl,,4',9);
{调制解调器 属性}
x:=winexec('rundll32.exe shell32.dll,Control_RunDLL Modem.cpl',9);
{网络}
x:=winexec('rundll32.exe shell32.dll,Control_RunDLL Netcpl.cpl',9);
{密码 属性}
x:=winexec('rundll32.exe shell32.dll,Control_RunDLL Password.cpl',9);
{扫描仪与数字相机 属性}
x:=winexec('rundll32.exe shell32.dll,Control_RunDLL Sticpl.cpl',9);
{系统 属性-常规}
x:=winexec('rundll32.exe shell32.dll,Control_RunDLL Sysdm.cpl,,0',9);
{系统 属性-设备管理器}
x:=winexec('rundll32.exe shell32.dll,Control_RunDLL Sysdm.cpl,,1',9);
{系统 属性-硬件配置文件}
x:=winexec('rundll32.exe shell32.dll,Control_RunDLL Sysdm.cpl,,2',9);
{系统 属性-性能}
x:=winexec('rundll32.exe shell32.dll,Control_RunDLL Sysdm.cpl,,3',9);
{日期/时间 属性}
x:=winexec('rundll32.exe shell32.dll,Control_RunDLL timedate.cpl',9);
{电源管理 属性}
x:=winexec('rundll32.exe shell32.dll,Control_RunDLL Powercfg.cpl',9);
{拨号属性}
x:=winexec('rundll32.exe shell32.dll,Control_RunDLL Telephon.cpl',9);


将图表变为真彩色
HKEY——CURRENT——USER
Control Panel
Control Panel
windowmetrics    新建字符串值 SHELL ICON BPP “16”

TOP

发新话题