teb源码
① LoadLibrary一个DLL时,系统做了哪些事
上源代码
主要功能:启动NotePad,在NotePad进程里创建RemoteThread加载我们自己的DLL,DLL加载时创建一个托盘,SubClass NotePad的主窗口,在标题栏上画一个Button。
HMODULE
LoadLibraryW(
LPCWSTR lpwLibFileName
)
{
return LoadLibraryExW( lpwLibFileName, NULL, 0 );
}
HMODULE
LoadLibraryExW(
LPCWSTR lpwLibFileName,
HANDLE hFile,
DWORD dwFlags
)
{
LPWSTR TrimmedDllName;
LPWSTR AllocatedPath;
NTSTATUS Status;
HMODULE hMole;
UNICODE_STRING DllName_U, AppPathDllName_U;
UNICODE_STRING AllocatedPath_U;
ULONG DllCharacteristics;
extern PLDR_DATA_TABLE_ENTRY BasepExeLdrEntry;
TrimmedDllName = NULL;
DllCharacteristics = 0;
if (dwFlags & DONT_RESOLVE_DLL_REFERENCES) {
DllCharacteristics |= IMAGE_FILE_EXECUTABLE_IMAGE;
}
RtlInitUnicodeString(&DllName_U, lpwLibFileName);
//
// Quick check to see if dll being loaded is the main exe. For some reason
// hook stuff tends to do this and this is worst path through the loader
//
if ( !(dwFlags & LOAD_LIBRARY_AS_DATAFILE) && BasepExeLdrEntry && (DllName_U.Length == BasepExeLdrEntry->FullDllName.Length) ){
if ( RtlEqualUnicodeString(&DllName_U,&BasepExeLdrEntry->FullDllName,TRUE) ) {
return (HMODULE)BasepExeLdrEntry->DllBase;
}
}
//
// check to see if there are trailing spaces in the dll name (Win95 compat)
//
if ( DllName_U.Length && DllName_U.Buffer[(DllName_U.Length-1)>>1] == (WCHAR)' ') {
TrimmedDllName = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG( TMP_TAG ), DllName_U.MaximumLength);
if ( !TrimmedDllName ) {
BaseSetLastNTError(STATUS_NO_MEMORY);
return NULL;
}
RtlCopyMemory(TrimmedDllName,DllName_U.Buffer,DllName_U.MaximumLength);
DllName_U.Buffer = TrimmedDllName;
while (DllName_U.Length && DllName_U.Buffer[(DllName_U.Length-1)>>1] == (WCHAR)' ') {
DllName_U.Buffer[(DllName_U.Length-1)>>1] = UNICODE_NULL;
DllName_U.Length -= sizeof(WCHAR);
DllName_U.MaximumLength -= sizeof(WCHAR);
}
}
//
// If DLL redirection is on for this application, we check to see if the DLL requested
// (without path qualification) exists in the app. (EXE) folder. If so, we load that.
// Else we fall back to regular search logic.
//
if (gDoDllRedirection && DllName_U.Length) {
Status = ComputeRedirectedDllName(&DllName_U, &AppPathDllName_U) ;
if(!NT_SUCCESS(Status)) {
if ( TrimmedDllName ) {
RtlFreeHeap(RtlProcessHeap(), 0, TrimmedDllName);
}
BaseSetLastNTError(Status);
return NULL;
}
if (RtlDoesFileExists_U(AppPathDllName_U.Buffer)) {
DllName_U.Buffer = AppPathDllName_U.Buffer ;
DllName_U.MaximumLength = AppPathDllName_U.MaximumLength ;
DllName_U.Length = AppPathDllName_U.Length;
}
}
//
// Determine the path that the program was created from
//
AllocatedPath = BaseComputeProcessDllPath(
dwFlags & LOAD_WITH_ALTERED_SEARCH_PATH ? DllName_U.Buffer : NULL,
GetEnvironmentStringsW()
);
if ( !AllocatedPath ) {
Status = STATUS_NO_MEMORY;
if ( TrimmedDllName ) {
RtlFreeHeap(RtlProcessHeap(), 0, TrimmedDllName);
}
goto l;
}
RtlInitUnicodeString(&AllocatedPath_U, AllocatedPath);
try {
if (dwFlags & LOAD_LIBRARY_AS_DATAFILE) {
#ifdef WX86
// LdrGetDllHandle clears UseKnownWx86Dll, but the value is
// needed again by LdrLoadDll.
BOOLEAN Wx86KnownDll = NtCurrentTeb()->Wx86Thread.UseKnownWx86Dll;
#endif
Status = LdrGetDllHandle(
AllocatedPath_U.Buffer,
NULL,
&DllName_U,
(PVOID *)&hMole
);
if (NT_SUCCESS( Status )) {
#ifdef WX86
NtCurrentTeb()->Wx86Thread.UseKnownWx86Dll = Wx86KnownDll;
#endif
goto alreadyLoaded;
}
Status = BasepLoadLibraryAsDataFile( AllocatedPath_U.Buffer,
&DllName_U,
(PVOID *)&hMole
);
}
else {
alreadyLoaded:
Status = LdrLoadDll(
AllocatedPath_U.Buffer,
&DllCharacteristics,
&DllName_U,
(PVOID *)&hMole
);
}
if ( TrimmedDllName ) {
RtlFreeHeap(RtlProcessHeap(), 0, TrimmedDllName);
TrimmedDllName = NULL;
}
RtlFreeHeap(RtlProcessHeap(), 0, AllocatedPath);
}
except (EXCEPTION_EXECUTE_HANDLER) {
Status = GetExceptionCode();
if ( TrimmedDllName ) {
RtlFreeHeap(RtlProcessHeap(), 0, TrimmedDllName);
}
RtlFreeHeap(RtlProcessHeap(), 0, AllocatedPath);
}
l:
if (gDoDllRedirection) {
// We would have led had we not been able to allocate this buffer in re-direction case.
RtlFreeHeap(RtlProcessHeap(), 0, AppPathDllName_U.Buffer);
}
if (!NT_SUCCESS(Status) ) {
BaseSetLastNTError(Status);
return NULL;
}
else {
return hMole;
}
}
NTSTATUS
BasepLoadLibraryAsDataFile(
IN PWSTR DllPath OPTIONAL,
IN PUNICODE_STRING DllName,
OUT PVOID *DllHandle
)
{
WCHAR FullPath[ MAX_PATH ];
PWSTR FilePart;
HANDLE FileHandle;
HANDLE MappingHandle;
LPVOID DllBase;
PIMAGE_NT_HEADERS NtHeaders;
PTEB Teb;
Teb = NtCurrentTeb();
*DllHandle = NULL;
if (!SearchPathW( DllPath,
DllName->Buffer,
L".DLL",
MAX_PATH,
FullPath,
&FilePart
)
) {
return Teb->LastStatusValue;
}
FileHandle = CreateFileW( FullPath,
GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_DELETE,
NULL,
OPEN_EXISTING,
0,
NULL
);
if (FileHandle == INVALID_HANDLE_VALUE) {
return Teb->LastStatusValue;
}
MappingHandle = CreateFileMappingW( FileHandle,
NULL,
PAGE_READONLY,
0,
0,
NULL
);
CloseHandle( FileHandle );
if (MappingHandle == NULL) {
return Teb->LastStatusValue;
}
DllBase = MapViewOfFileEx( MappingHandle,
FILE_MAP_READ,
0,
0,
0,
NULL
);
CloseHandle( MappingHandle );
if (DllBase == NULL) {
return Teb->LastStatusValue;
}
NtHeaders = RtlImageNtHeader( DllBase );
if (NtHeaders == NULL) {
UnmapViewOfFile( DllBase );
return STATUS_INVALID_IMAGE_FORMAT;
}
*DllHandle = (HANDLE)((ULONG_PTR)DllBase | 0x00000001);
LdrLoadAlternateResourceMole(*DllHandle, FullPath);
return STATUS_SUCCESS;
}
NTSTATUS
LdrLoadDll (
IN PWSTR DllPath OPTIONAL,
IN PULONG DllCharacteristics OPTIONAL,
IN PUNICODE_STRING DllName,
OUT PVOID *DllHandle
){
return LdrpLoadDll(DllPath,DllCharacteristics,DllName,DllHandle,TRUE);
}
② GET参数怎么用
后台解密使用且get能传送255内字节所推荐使用get传递参数参数通post据我web发经验看能用get式传都能转post式看前台技术掌握
③ 手机qq空间背景图片怎么保存
QQ空间的背景图片是无法直接保存到手机上,我可以推荐一个方法。先用手机截屏背景图片,然后进行修剪,这样也是可以拿到QQ空间背景图片。
打开后保存就行了
④ 怎么保存qq空间的背景图片到手机上
QQ空间的背景图片是无法直接保存到手机上,我可以推荐一个方法。
先用手机截屏背景图片,然后进行修剪,这样也是可以拿到QQ空间背景图片。
把截屏的QQ空间背景图片使用手机修剪功能来修剪,修剪后就剩下QQ空间背景图片。
⑤ 病毒是怎么写出来的
汇编语言底层,灵活,速度快,体积小的优势能将一个病毒程序发挥到极至,通常一个程序写出来才几千字节就包含了所有的功能。一般一个病毒都有如下几个功能:
一 代码重定位
二 自己找到所需API地址
三 搜索文件、目录
四 感染文件
五 破坏系统或文件(随便你了)
其中一,二项功能是必要的,五项功能是可选的。而一个病毒程序感染文件的功能是它的核心,是衡量它质量的重要标准。
(一)代码的重定位
一个变量或函数其实是一个内存地址,在编译好后,程序中的指令通过变量或函数的内存地址再去存取他们,这个地址是个绝对地址。如果你将代码插入到其他任何地方,再通过原来编译时产生的地址去找他们就找不到了,因为他们已经搬家了。但是,在写程序时考虑到这个问题,可以在代码最开始,放上几行代码取得程序基地址,以后变量和函数作为偏移地址,显式的加上这个基地址就能顺利找到了,这就是重定位。就象这段代码。
Call getbaseaddress
Getbaseaddress:pop ebx
Sub ebx,offset getbaseaddress
Mov eax,dword ptr [ebx+Var1]
如果使用宏汇编语言写病毒,请尽量使用ebx做基地址指针,不要使用ebp,因为ebp在调用带参数的函数时会改变。
(二)自己取得所需的API地址
一个win32程序文件,所调用的API函数地址,是由系统填入到程序文件中描述各类数据位置的数据结构中的。而病毒作为一个残废是享受不到这个待遇的。因为你在把病毒的代码插入目标程序时没有把这些描述数据存放位置的数据结构信息也弄进去。它被插入到其他目标程序后就成了只有代码的残废儿童:(所以作为一个残废儿童,应当自力更生。自己搜寻自己需要的API地址。目标程序文件就包含了我们需要的东西,需要自己去找。目标程序文件只要还是win32程序,它的地址空间中就包含的有Kernel32.dll。如果找到了它,就能找到其他任何的东东。第一步,搜寻kernel32.dll的基地址。当然了,整个地址空间有4GB,可供搜索的用户进程空间也有2GB。在2GB中搜索,太吓人了。
在程序被加载后,加载程序会调用程序的主线程的第一条指令的位置。它使用的指令是CALL,就是说,程序还没执行,堆栈区里就有了一个返回地址了,这个返回地址指向的是加载程序,而加载程序是包含在KERNEL32.dll中的,顺着它向上找,就能找到kernel32.dll的基地址了。当然也不是一个字节一个字节的挨者找,而是一个页面一个页面地找。因为win32下,代码或数据的开始位置总是页面单位(windows平台下为4kb)对齐的。Kernel32.dll是一个PE文件,按比较PE文件dos签名标志和PE签名标志的方法找。另外还有个办法是通过SHE技术找。这是最好的办法了,前一个办法因为堆栈是动态的原因不稳定,一般只能将获取地址的代码块放在最开头,这个方法完全是与堆栈无关的,放在哪里执行都不会出错,如果你的病毒需要用一些远程线程之类的技术,最好用这个方法。
SHE结构,第一个成员指向下一个SEH结构,如果是最后一个那么它的值就是0ffffffffh。第二个成员指向异常处理函数,如果是最后一个SHE结构且没有指定的话,缺省的是SetUnhandlederExceptionFilter函数地址。当异常触发这个函数时就会弹出一个对话框,问你发不发送错误。98下显示蓝屏。这个函数是包含在KERNEL32.dll中的,只要取得它的地址向上找就能找到KERNEL32.dll的基地址了。在说SHE时总忘不了TEB,TEB是创建一个线程时分配的线程相关的数据结构,SHE只是它开头第一个数据结构体而已。它还包含了其他许多重要的东西,TEB由FS段选择器指向,有兴趣的查查资料,这里篇幅原因就不再多说了。接着上面的,看看如何找SetUnhanderExceptionFilter函数地址。先根据“下一个”SHE结构的值定位到最后一个SHE结构,这时取出she处理函数的地址,就是SetUnHandleredEceptionFilter函数地址了,以页面为单位向上找就可以找到Kernel32.dll了/
得到Kernel32.dll的基地址后,定位到它的导出表,找出GetProcAddress地址再利用GetProcAddress就能找到其他任何所需要的函数了。在搜索API时应该注意API的名字,API的名字实际的导出名字很有可能不是你调用时的名字,windows下很多API都有两个版本ANSI版和UNICODE版,ANSI版函数名后缀带个A,比如CreateWindowExA,,而UNICODE版的函数名带个W后缀,比如CreateWindowExW。不过考虑到麻烦问题,现有的很多编译器都不让你写后缀,只是在编译的时候根据你程序是ANSI版的还是UNICODE版的自动改名字。Win2K以后的API函数都是Unicode 版本的,如果调用ANSI版本的函数,系统只是将函数中的字符串通过进程默认堆将其转换成Unicode字符串,再调用Unicode版的API。Unicode是个发展方向,大家应该养成使用它的习惯而不是ANSI。
(三)搜索文件、目录
主要是用FindFirstFile,FindNextFile,FindClose.这三个函数实现。值得注意的是在用“*.*”搜索字符串时得到的是程序文件所在目录的所有文件和目录。而GetCurrentDirectory取得的是系统当前的目录。后者是随时会随着用户的操作而改变的,前者只会随着目标程序文件的位置改变而改变。搜索需要感染的目录和文件时应该重点搜索windows安装目录(GetWindowsDirectory),系统目录(GetSystemDIrectory),当前目录(GetCurrentDirectory) ,当然程序当前目录也是不可放过的,比如,把QQ感染了,QQ目录底下那么多常常使用的程序文件,比如珊瑚虫外挂,邮箱工具等等都是你的盘中餐了。最喜欢感染的地方还是系统中各个进程所在的目录,那些才是用户最常用的,我的遂宁一号病毒是通过代码插入的办法做到这点的,很麻烦,且很不稳定。常常莫名其妙的使被插入进程在插入时结束掉,虽然可以用SHE避免,但是还是没多大效果。
(四)感染文件
所谓感染就是将病毒程序的代码插入到目标程序中,然后让目标程序先执行病毒程序的代码。
⑥ 网站里面有几个ASP文件看不懂
应该是VBScript.Encode加密了.
尝试解密,再看一下是代码是什么.就知道了.
不过,倒着看,里面有提权的字眼,可以肯定这是一个木马文件了.
⑦ WinDbg怎么用
什么是WinDBG? WinDbg是微软开发的免费源码级调试工具。Windbg可以用于Kernel模式调试和用户模式调试,还可以调试Dump文件。由于大部分程序员不需要做Kernel模式调试, 我在这篇文章中不会介绍Kernel模式调试。Kernel模式调试对学习Windows核心极有帮助。如果你对此感兴趣,可以阅读Inside Windows 2000和Windbg所带的帮助文件。这篇文章得主要目的是介绍WINDBG的主要功能以及相关的命令。关于这些命令的详细语法,请参阅帮助文件。对文章中提到的许多命令,WINDBG有相应的菜单选项。如何得到帮助在命令(Command)窗口中输入.hh 命会调出帮助文件令。.hh keyword会显示关于keyword的详细命令。启动DebuggerWindbg可以用于如下三种调试:远程调试:你可以从机器A上调试在机器B上执行的程序。具体步骤如下:
? 在机器B上启动一个调试窗口(Debug Session)。你可以直接在Windbg下运行一个程序或者将Windbg附加(Attach)到一个进程。? 在机器B的Windbg命令窗口上启动一个远程调试接口(remote):.server npipe:pipe=PIPE_NAMEPIPE_NAME是该接口的名字。? 在机器A上运行:windbg –remote npipe:server=SERVER_NAME,pipe=PIPE_NAMESERVER_NAME是机器B的名字。Dump文件调试:如果在你的客户的机器上出现问题,你可能不能使用远程调试来解决问题。你可以要求你的用户将Windbg附加到出现问题的进程上,然后在命令窗口中输入:
.mp /ma File Name创建一个Dump文件。在得到Dump文件后,使用如下的命令来打开它:windbg –z DUMP_FILE_NAME本地进程调试:你可以在Windbg下直接运行一个程序:
Windbg “path to executable” arguments 也可以将Windbg附加到一个正在运行的程序: Windbg –p “process id” Windbg –pn “process name” 注意有一种非侵入(Noninvasive)模式可以用来检查一个进程的状态并不进程的执行。当然在这种模式下无法控制被调试程序的执行。这种模式也可以用于查看一个已经在Debugger控制下运行的进程。具体命令如下: Windbg –pv –p “process id” Windbg –pv –pn “process name” 调试多个进程和线程如果你想控制一个进程以及它的子进程的执行,在Windbg的命令行上加上-o选项。Windbg中还有一个新的命令.childdbg 可以用来控制子进程的调试。如果你同时调试几个进程,可以使用 | 命令来显示并切换到不同的进程。在同一个进程中可能有多个线程。~命令可以用来显示和切换线程。调试前的必备工作在开始调试前首先要做的工作是设置好符号(Symbols)路径。没有符号,你看到的调用堆栈基本上毫无意义。Microsoft的操作系统符号文件(PDB)是对外公开的。另外请注意在编译你自己的程序选择生成PDB文件的选项。如果设置好符号路径后,调用堆栈看起来还是不对。可以使用lm, !sym noisy, !reload 等命令来验证符号路径是否正确。Windbg也支持源码级的调试。在开始源码调试前,你需要用.srcpath设置源代码路径。如果你是在生成所执行代码的机器上进行调试,符号文件中的源码路径会指向正确的位置,所以不需要设置源代码路径。如果所执行代码是在另一台机器上生成的,你可以将所用的源码拷贝(保持原有的目录结构)的一个可以访问的文件夹(可以是网络路径)并将源代码路径设为该文件夹的路径。注意如果是远程调试,你需要使用.lsrcpath来设置源码路径。静态命令:显示调用堆栈:在连接到一个调试窗口后,首先要知道的就是程序当前的执行情况k* 命令显示当前线程的堆栈。~*kb会显示所有线程的调用堆栈。如果堆栈太长,Windbg只会显示堆栈的一部分。.kframes可以用来设置缺省显示框架数。显示局部变量:接下来要做通常是用dv显示局部变量的信息。CTRL+ALT+V可以切换到更详细的显示模式。关于dv要注意的是在优化过的代码中dv的输出极有可能是不准确的。这时后你能做的就是阅读汇编代码来发现你感兴趣的值是否存储在寄存器中或堆栈上。有时后当前的框架(Frame)上可能找不到你想知道的数据。如果该数据是作为参数传到当前的方法中的,可以读一读上一个或几个框架的汇编代码,有可能该数据还在堆栈的某个地址上。静态变量是储存在固定地址中的,所以找出静态变量的值较为容易。.Frame(或者在调用堆栈窗口中双击)可以用来切换当前的框架。注意dv命令显示的是当前框架的内容。你也可在watch窗口中观察局部变量的值。显示类和链表: dt可以显示数据结构。比如dt PEB 会显示操作系统进程结构。在后面跟上一个进程结构的地址会显示该结构的详细信息:dt PEB 7ffdf000。Dl命令可以显示一些特定的链表结构。显示当前线程的错误值:!gle会显示当前线程的上一个错误值和状态值。!error命令可以解码HRESULT。搜索或修改内存:使用s 命令来搜索字节,字或双字,QWORD或字符串。使用e命令来修改内存。计算表达式:?命令可以用来进行计算。关于表达式的格式请参照帮助文档。使用n命令来切换输入数字的进制。显示当前线程,进程和模块信息:!teb显示当前线程的环境信息。最常见的用途是查看当前线程堆栈的起始地址,然后在堆栈中搜索值。!peb显示当前进程的环境信息,比如执行文件的路径等等。lm显示进程中加载的模块信息。显示寄存器的值:r命令可以显示和修改寄存器的值。如果要在表达式中使用寄存器的值,在寄存器名前加@符号(比如@eax)。显示最相近的符号:ln Address。如果你有一个C++对象的指针,可以用来ln来查看该对象类型。 查找符号:x命令可以用来查找全局变量的地址或过程的地址。x命令支持匹配符号。x kernel32!*显示Kernel32.dll中的所有可见变量,数据结构和过程。查看lock:!locks显示各线程的锁资源使用情况。对调试死锁很有用。查看handle:!handle显示句柄信息。如果一段代码导致句柄泄漏,你只需要在代码执行前后使用!handle命令并比较两次输出的区别。有一个命令!htrace对调试与句柄有关的Bug非常有用。在开始调试前输入:!htrace –enable 然后在调试过程中使用!htrace handle_value 来显示所有与该句柄有关的调用堆栈。显示汇编代码:u。程序执行控制命令:设置代码断点:bp/bu/bm 可以用来设置代码断点。你可以指定断点被跳过的次数。假设一段代码KERNEL32!SetLastError在运行很多次后会出错,你可以设置如下断点: bp KERNEL32!SetLastError 0x100.在出错后使用bl 来显示断点信息(注意粗体显示的值):0 e 77e7a3b0 004f (0100) 0:*** KERNEL32!SetLastError重新启动调试(.restart命令)并设置如下的断点:bp Kernel32!SetLastError 0x100-0x4fDebugger会停在出错前最后一次调用该过程的地方。你可以指定断点被激活时Debugger应当执行的命令串。在该命令串中使用J命令可以用来设置条件断点:bp `mysource.cpp:143` "j (poi(MyVar)”0n20) ''; 'g' "上面的断点只在MyVar的值大于32时被激活(g命令条件断点的用途极为广泛。你可以指定一个断点只在特殊的情况下被激活,比如传入的参数满足一定的条件,调用者是某个特殊的过程,某个全局变量被设为特殊的值等等。设置内存断点:ba可以用来设置内存断点。调试过程中一个常见的问题是跟踪某些数据的变化。如下的断点:ba w4 0x40000000 "kb; g"可以打印出所有修改0x40000000的调用堆栈。控制程序执行:p, pa,t, ta等命令可以用来控制程序的执行。控制异常和事件处理:Debugger的缺省设置是跳过首次异常(first chance expcetion),在二次异常(second chance exception)时中断程序的执行。sx命令显示Debugger的设置。sxe和sxd可以改变Debugger的设置。 sxe clr可以控制Debugger在托管异常发生时中断程序的执行。常用的Debugger事件有: av 访问异常 eh C++异常 clr 托管异常 ld 模块加载-c 选项可以用来指定在事件发生时执行的调试命令。