摘要: 本人進2年來主要在做windbg調試相關的工作, 有一些心得和體會. 我會逐片寫在我blog中,希望對大家有用. windbg調試最重要的是要對系統的方方面面有比較深入的了解. 只有了解了系統工作原理才能夠順藤摸瓜. 一步步展開線索. windbg基礎篇...
閱讀全文
posted @
2009-08-22 13:47 Only Soft 閱讀(5261) |
評論 (4) |
編輯 收藏
寄存器沒有地址
也就是寄存器存放著存儲器的地址.
CPU通過寄存器中存放的存儲器地址來訪問存儲器中的數據
X86系列的處理器中的寄存器較少,所以
沒有給cpu中的寄存器進行編址,而是直接對這些寄存器進行了命名.在訪問寄存器的時候只要直接使用寄存器名就可以了.
lea指令舉例:
lea 取得地址(第二個參數)后放入到前面的寄存器。
如:lea edi, ebp ,就是將ebp里存儲的地址放入edi, 讓edi也只想這個地址。
其實就是edi 指向ebp指向的存儲器地址
又如: lea edi, [ebp+0cch], []中代表存儲器地址, 即ebp指向的存儲器地址+0cch偏移。
再舉一個例子:
mov ecx,30h
mov eax,0CCCCCCCCh
rep stos dword ptr es:[edi]
stos是串存儲指令,他的功能是將eax中的數據存入edi寄存器所指向的存儲器地址中。同時,edi會增加4(字節數)
rep是指令重復執行ecx中填寫的次數
posted @
2010-01-22 18:57 Only Soft 閱讀(320) |
評論 (0) |
編輯 收藏
從FS寄存器獲取當前線程ID
int GetThreadId()
{
int ithread = 0;
_asm{
xor esi , esi
mov eax, fs:[esi+18h]
mov ecx, [eax+ 20h]
mov eax, [eax+ 24h]
mov dword ptr[ithread], eax
}
return ithread;
}
從FS寄存器獲取當前進程ID
int GetProcessId()
{
int iProcess = 0;
_asm{
xor esi , esi
mov eax, fs:[esi+18h]
mov ecx, [eax+ 20h]
mov eax, [eax+ 24h]
mov dword ptr[iProcess ], ecx
}
return iProcess ;
}
原理:
1.fs:18h 地址指向線程環境塊_TEB
打開windbg可以證明:
0:028> dd fs:18h L1
0053:00000018
7eeb80000:028> !teb
TEB at
7eeb8000 ExceptionList: 1f8ff15c
StackBase: 1f900000
StackLimit: 1f8fc000
SubSystemTib: 00000000
FiberData: 00001e00
ArbitraryUserPointer: 00000000
Self: 7eeb8000
EnvironmentPointer: 00000000
ClientId: 00001a30 . 00001408
RpcHandle: 00000000
Tls Storage: 133d2718
PEB Address: 7efde000
LastErrorValue: 0
LastStatusValue: c0000302
Count Owned Locks: 0
HardErrorMode: 0
2. 在_TEB中找到線程ID和進程ID
0:028> dt ntdll!_TEB
+0x000 NtTib : _NT_TIB
+0x01c EnvironmentPointer : Ptr32 Void
+0x020 ClientId : _CLIENT_ID
0:028> dt ntdll!_CLIENT_ID
+0x000 UniqueProcess : Ptr32 Void >進程ID
+0x004 UniqueThread : Ptr32 Void >線程ID
當然從TEB又可以找到_PEB的地址,從_PEB里面可以獲取到更多的信息。暫且擱筆~~
posted @
2010-01-20 15:10 Only Soft 閱讀(3513) |
評論 (0) |
編輯 收藏
在驅動中分配內存,通常你的驅動會向NT VMM請求內存,這是你必須決定你的內存是可分頁的或者非可分頁的。
分配原則:盡量使用可分頁內存,但是必須注意高等級IRQL執行不允許page fault。所以不允許采用可分頁內存。可以使用PAGED_CODE();宏來檢查。
非分頁內存在系統中是一個有限的資源,取決于操作系統和物理內存大小. (NT VMM使用一個私有算法來計算非分頁大小,這個算法使用物理內存總是作為計算因子來計算。)
NT提供如下例程來分配內存:
ExAllocatePool();
ExAllocatePoolWithQuota();
ExAllocatePoolWithTag();
ExAllocatePoolWithQuotaTag
調用以上例程分配內存是必須制定內存的類型:
NonPagedPool
PagedPool
NonPagedPoolMustSuccessed.
......................
關于非分頁內存碎片問題:
本來初始化的時候地址都是相鄰的非分頁池會變成碎片。而且VMM在托大的時候也不保證地址相鄰。
如果請求的分配或者釋放小塊內存(小于一個PAGE_SIZE),可能導致物理內存碎片化。這回給系統帶來各種各樣的問題,包括降低系統性能和分配內存失敗的情況。
解決辦法使用旁視列表,旁視列表是一個NT4.0開始提供的一個內存分配方式;具體請參考WDK docment.
順便提一下內核棧:
每個在NT平臺的線程有一個用戶棧在用戶模式執行的時候使用,一個內核棧在內核模式執行的時候使用。當線程請求系統服務而切換到內核模式的時候,陷阱機制會切換棧。用分配和線程的內核空間棧來覆蓋用戶空間棧。
在NT3.51之前,內核棧限制在兩頁的內存中。NT4.0開始增加到12KB.必須要謹慎的在棧上使用變量以節省占空間,防止超過限制而是系統停止。
posted @
2009-11-15 23:57 Only Soft 閱讀(888) |
評論 (0) |
編輯 收藏
首先是參數說明宏。參數說明宏一般都是空宏,最常見的是IN和OUT。其實定義很簡單,如下所示:
#define IN
#define OUT
這樣一來,IN和OUT就被定義成了空。無論出現在代碼中的任何地方,對代碼都不會有什么實質的影響。在WDK的代碼中,用來作為函數的說明。IN表示這個參數用于輸入;OUT表示這個參數用來返回結果。比如下面的例子:
NTSTATUS
ZwQueryInformationFile(
IN HANDLE FileHandle,
OUT PIO_STATUS_BLOCK IoStatusBlock,
OUT PVOID FileInformation,
IN ULONG Length,
IN FILE_INFORMATION_CLASS FileInformationClass
);
IN和OUT是比較傳統的參數說明宏。在WDK中到處可見更復雜的參數說明宏,比如下面的例子:
VOID
NdisProtStatus(
IN NDIS_HANDLE ProtocolBindingContext,
IN NDIS_STATUS GeneralStatus,
__in_bcount(StatusBufferSize) IN PVOID StatusBuffer,
IN UINT StatusBufferSize
)
其中的__in_bcount不但說明參數StatusBuffer是一個輸入參數,而且說明了StatusBuffer作為一個緩沖區,它的字節長度被另一個參數StatusBufferSize所指定。讀者再見到類似的說明宏,就以字面意思理解即可。
然后是指定函數位置的預編譯指令。比如下面的例子:
NTSTATUS
ZwQueryInformationFile(
IN HANDLE FileHandle,
OUT PIO_STATUS_BLOCK IoStatusBlock,
OUT PVOID FileInformation,
IN ULONG Length,
IN FILE_INFORMATION_CLASS FileInformationClass
);
IN和OUT是比較傳統的參數說明宏。在WDK中到處可見更復雜的參數說明宏,比如下面的例子:
VOID
NdisProtStatus(
IN NDIS_HANDLE ProtocolBindingContext,
IN NDIS_STATUS GeneralStatus,
__in_bcount(StatusBufferSize) IN PVOID StatusBuffer,
IN UINT StatusBufferSize
)
其中的__in_bcount不但說明參數StatusBuffer是一個輸入參數,而且說明了StatusBuffer作為一個緩沖區,它的字節長度被另一個參數StatusBufferSize所指定。讀者再見到類似的說明宏,就以字面意思理解即可。
然后是指定函數位置的預編譯指令。比如下面的例子:
#pragma alloc_text(INIT, DriverEntry)
#pragma alloc_text(PAGE, NdisProtUnload)
#pragma alloc_text(PAGE, NdisProtOpen)
#pragma alloc_text(PAGE, NdisProtClose)
#pragma alloc_text
這個宏僅僅用來指定某個函數的可執行代碼在編譯出來后在sys文件中的位置。內核模塊編譯出來之后是一個PE格式的sys文件,這個文件的代碼段(text段)中有不同的節(Section),不同的節被加載到內存中之后處理情況不同。讀者需要關心的主要是3種節:INIT節的特點是在初始化完畢之后就被釋放。也就是說,就不再占用內存空間了。PAGE節的特點是位于可以進行分頁交換的內存空間,這些空間在內存緊張時可以被交換到硬盤上以節省內存。如果未用上述的預編譯指令處理,則代碼默認位于PAGELK節,加載后位于不可分頁交換的內存空間中。
函數DriverEntry顯然只需要在初始化階段執行一次,因此這個函數一般都用#pragma alloc_text(INIT, DriverEntry)使之位于初始化后立刻釋放的空間內。為了節約內存,可以把很多函數放在PAGE節中。但是要注意:放在PAGE節中的函數不可以在Dispatch級調用,因為這種函數的調用可能誘發缺頁中斷。但是缺頁中斷處理不能在Dispatch級完成。為此,一般都用一個宏PAGED_CODE()進行測試。如果發現當前中斷級為Dispatch級,則程序直接報異常,讓程序員及早發現。示例如下:
#pragma alloc_text(PAGE, SfAttachToMountedDevice)
……
NTSTATUS
SfAttachToMountedDevice (
IN PDEVICE_OBJECT DeviceObject,
IN PDEVICE_OBJECT SFilterDeviceObject
)
{
PSFILTER_DEVICE_EXTENSION newDevExt =
SFilterDeviceObject->DeviceExtension;
NTSTATUS status;
ULONG i;
PAGED_CODE();
…
本文摘自《寒江獨釣:Windows內核安全編程》
posted @
2009-11-15 23:03 Only Soft 閱讀(697) |
評論 (0) |
編輯 收藏
User32.dll,kernel32.dll,shell32.dll,gdi32.dll,rpcrt4.dll,comctl32.dll,advapi32.dll,version.dll等dll代表了Win32 API的基本提供者;
Win32 API中的所有調用最終都轉向了ntdll.dll,再由它轉發至ntoskrnl.exe。ntdll.dll是本機 API用戶模式的終端。真正的接口在ntoskrnl.exe里完成。事實上,內核模式的驅動大部分時間調用這個模塊,如果它們請求系統服務。Ntdll.dll的主要作用就是讓內核函數的特定子集可以被用戶模式下運行的程序調用。Ntdll.dll通過軟件中斷int 2Eh進入ntoskrnl.exe,就是通過中斷門切換CPU特權級。
Ntdll.dll 上面的相關API函數原型和參數都沒有文檔化(Undocumented ):
http://undocumented.ntinternals.net/ 這里提供了Ntdll.dll部分未公開函數的原型.
理解window API及函數原型對我們的調試將是非常重要的: 因為你時常需要去察看一些函數的參數,或者根據參數找到某些輸入指針.
例如:
17 Id: a84.cc4 Suspend: 1 Teb: 7ff3a000 Unfrozen
ChildEBP RetAddr Args to Child
187ffdb8 77845e6c 7782fc72 00001938 00000000 ntdll!KiFastSystemCallRet
187ffdbc 7782fc72 00001938 00000000 00000000 ntdll!NtWaitForSingleObject+0xc
187ffe20 7782fb56 00000000 00000000 00000000 ntdll!RtlpWaitOnCriticalSection+0x13e
187ffe48 01b05d13 0x77c8ba60 81fa55ed 028766c8 ntdll!RtlEnterCriticalSection+0x150
從堆棧可以看出線程17 正在進入某一個臨界區. 0x77c8ba60 就是傳入的臨界值 參數.
17> !cs 0x77c8ba60 --> !cs 是用來查看臨界區信息的命令
DebugInfo = 0x77fbde20
Critical section = 0x77c8ba60 (GDI32!semColorSpaceCache+0x0)
LOCKED
LockCount = 0x0
OwningThread = 0x00000dd8
RecursionCount = 0x1
LockSemaphore = 0x0
SpinCount = 0x00000000
可以看到 LOCKED 代表臨界區是鎖定狀態. 即被占用.
OwningThread 即是占用線程.
臨界區信息結構定義在ntdll, 可以使用如下指令進行察看.
> dt ntdll!_RTL_CRITICAL_SECTION
+0x000 DebugInfo : Ptr32 _RTL_CRITICAL_SECTION_DEBUG
+0x004 LockCount : Int4B
+0x008 RecursionCount : Int4B
+0x00c OwningThread : Ptr32 Void
+0x010 LockSemaphore : Ptr32 Void
+0x014 SpinCount : Uint4B
察看某個動態庫函數表的指令:
x ntdll!*
x kernal!*
察看結構體定義:
dt ntdll!*
任何動態庫包括window 32的用戶態dll 和用戶自定義動態庫都是生長在進程內存空間上的.
DLL 沒有自己的"私有"地址空間. 它們總是被影射到應用程序的虛擬地址空間,在需要時才會被讀取到物理內存中.
在本系列的其它章節我會談到虛擬地址空間的內容.
通過指令可以看到ntdll 被映射到77800000 ~ 7793c000的內存空間中.
> x *!
77800000 7793c000 ntdll (pdb symbols) c:\mylocalsymbols\ntdll.pdb\F0164DA71FAF4765B8F3DB4F2D7650EA2\ntdll.pdb
當你的代碼(線程)棧中出現地址范圍在 77800000 ~7793c000 之間的函數調用都表示在call NTDLL.dll
比如:
7 Id: a84.c34 Suspend: 1 Teb: 7ff3f000 Unfrozen
ChildEBP RetAddr Args to Child
089bfe8c 77845e6c 75a0179c 00000d98 00000000 ntdll!KiFastSystemCallRet
089bfe90 75a0179c 00000d98 00000000 00000000 ntdll!NtWaitForSingleObject+0xc
089bfefc 75c9f003 00000d98 ffffffff 00000000 KERNELBASE!WaitForSingleObjectEx+0x98
089bff14 75c9efb2 00000d98 ffffffff 00000000 kernel32!WaitForSingleObjectExImplementation+0x75
089bff28 69434fea 00000d98 ffffffff 0780c178 kernel32!WaitForSingleObject+0x12
WARNING: Stack unwind information not available. Following frames may be wrong.
此線程中WARNING: Stack unwind information not available. Following frames may be wrong.表示windbg無法翻譯或者找到對應symbols來顯示code stack. 這種錯誤往往是保存dump file時出現的某種異常信息.window也沒有給出合理的解釋.
以下是MSDN的原話:
In some cases, the stack trace function will fail in the debugger. This can be caused by a call to an invalid address that caused the debugger to lose the location of the return address; or you may have come across a stack pointer for which you cannot directly get a stack trace; or there could be some other debugger problem. In any case, being able to manually walk a stack is often valuable.
這時候你需要手動的進行恢復棧調用. 如果你了解每個動態庫的映射地址你就很容易進行分析了.
察看動態庫中每個函數映射的地址可以采用如下指令 :
x ntdll!
手動恢復棧的大致原理如下:
1. 列出線程環境信息
0:000> !teb
TEB at 7fffe000
ExceptionList: 0012ff88
StackBase: 00130000
StackLimit: 00126000
……….
2. 打開整個線程棧.
0:000> dds 00126000 00130000
3. 察看內存中所有可能是函數返回值.
>ln address
posted @
2009-08-24 11:20 Only Soft 閱讀(3094) |
評論 (0) |
編輯 收藏
摘要: 本人進2年來主要在做windbg調試相關的工作, 有一些心得和體會. 我會逐片寫在我blog中,希望對大家有用. windbg調試最重要的是要對系統的方方面面有比較深入的了解. 只有了解了系統工作原理才能夠順藤摸瓜. 一步步展開線索. windbg基礎篇...
閱讀全文
posted @
2009-08-22 13:47 Only Soft 閱讀(5261) |
評論 (4) |
編輯 收藏
以下是3D中,經常會碰到的一些紋理或者文件格式。僅供參考~~
TXT
Update: 2004-2-24
無任何格式的ASCII文本文件。
X文件
Update: 2004-2-24
復雜的幾何模型通常是由3D建模軟體創建并保存到文件中,Microsoft Direct3D使用的網格模型都是載入這些文件中的對象。
TIFF格式
Update: 2004-2-23
TIFF(Tag Image File Format有標簽的圖像文件格式)是Aldus在Mac初期開發的,目的是使掃描圖像標準化。它是跨越Mac與PC平臺最廣泛的圖像打印格式。TIFF使用LZW無損壓縮,大大減少了圖像體積。另外,TIFF格式最令人激動的功能是可以保存通道,這對于你處理圖像是非常有好處的。
JPEG格式
Update: 2004-2-23
JPEG(由Joint Photographic Experts Group“聯合圖形專家組”命名)是我們平時最常用的圖像格式。它是一個最有效、最基本的有損壓縮格式,被極大多數的圖形處理軟件所支持。JPEG格式的圖像還廣泛用于Web的制作。如果對圖像質量要求不高,但又要求存儲大量圖片,使用JPEG無疑是一個好辦法。
Amiga IFF格式
Update: 2004-2-23
Amiga是由Commodore開發的,由于該公司已退出計算機市場,因此,Amiga IFF格式也將漸漸地被廢棄。
PCX格式
Update: 2004-2-23
PCX是DOS下的古老程序PC PaintBrush固有格式的擴展名,因此這個格式已不受歡迎。
TGA格式
Update: 2004-2-23
TrueVision的TGA(Targa)和NuVista視頻板可將圖像和動畫轉入電視中,PC機上的視頻應用軟件都廣泛支持TGA格式。
Scitex CT格式
Update: 2004-2-23
Scitex CT格式支持灰度級圖像、RGB圖像、CMYK圖像。Photoshop可以打開諸如Scitex圖像處理設備的數字化圖像。
PDF格式
Update: 2004-2-23
PDF(Portable Document Format)是由Adobe Systems創建的一種文件格式,允許在屏幕上查看電子文檔。PDF文件還可被嵌入到Web的HTML文檔中。
PICT格式
Update: 2004-2-23
PICT是Mac上常見的數據文件格式之一。如果你要將圖像保存成一種能夠在Mac上打開的格式,選擇PICT格式要比JPEG要好,因為它打開的速度相當快。另外,你如果要在PC機上用Photoshop打開一幅Mac上的PICT文件,建議你在PC機上安裝QuickTime,否則,將不能打開PICT圖像。
BMP格式
Update: 2004-2-23
BMP(Windows Bitmap)是微軟開發的Microsoft Pain的固有格式,這種格式被大多數軟件所支持。BMP格式采用了一種叫RLE的無損壓縮方式,對圖像質量不會產生什么影響。
PNG格式
Update: 2004-2-23
PNG是專門為Web創造的。PNG格式是一種將圖像壓縮到Web上的文件格式,和GIF格式不同的是,PNG格式并不僅限于256色。
GIF格式
Update: 2004-2-23
GIF是輸出圖像到網頁最常采用的格式。GIF采用LZW壓縮,限定在256色以內的色彩。GIF格式以87a和89a兩種代碼表示。GIF87a嚴格支持不透明像素。而GIF89a可以控制那些區域透明,因此,更大地縮小了GIF的尺寸。
后面的文章將會對Gif格式做一個實現。請期待
posted @
2009-04-04 01:07 Only Soft 閱讀(565) |
評論 (0) |
編輯 收藏
本程序只關注對Gif紋理的實現。不對GIF加解密進行詳細的說明。
GIF文檔解析采用gif89a.h, gif89a.cpp實現。
gif89a 代碼下載
詳細紋理生成代碼:

bool Cmenu::CreateTextureFromGif()


{
HRESULT hr;
CGif89a* pGif = new CGif89a();
BOOL bopen = pGif->open("110743081.gif",true);
int index = 0;
LPCFRAME pFrame = pGif->getFrame(index);
if (!pFrame)
return false;


BYTE* pColorTable = pGif->getColorTable(index);
if (!pColorTable)
return false;

//create empty Texture.
hr = D3DXCreateTexture(m_pDevice,pFrame->imageWidth,pFrame->imageHeight,0,0,D3DFMT_X8B8G8R8,D3DPOOL_MANAGED,&m_pTexture[0]);
if(FAILED(hr))
return false;

D3DSURFACE_DESC textureDesc;
m_pTexture[0]->GetLevelDesc(0,&textureDesc);

if(textureDesc.Format != D3DFMT_X8B8G8R8)
return false;

D3DLOCKED_RECT locketrect;
hr = m_pTexture[0]->LockRect( 0,&locketrect,0,0 );
if(FAILED(hr))
return false;

BYTE* pBytes = (BYTE*)locketrect.pBits;
DWORD lPitch = locketrect.Pitch;

int idx_trs = pFrame->ctrlExt.trsFlag ? pFrame->ctrlExt.trsColorIndex : -1;

int x=0,y=0;
int sx, sy;
if(x<0)
sx = -x;
else
sx = 0;
if(y<0)
sy = -y;
else
sy = 0;


DWORD width = pFrame->imageWidth;

pBytes += lPitch*sy;
for( DWORD h=sy; y+h<pFrame->imageHeight; h++ )

{
DWORD* pDstData32 = ((DWORD*)pBytes) + sx;
WORD* pDstData16 = ((WORD*)pBytes) + sx;
BYTE* pPixel;

BYTE* pIdx = pFrame->dataBuf + (pFrame->imageWidth*(((y>0)?y:0)+h) + ((x>0)?x:0));

for( DWORD w=sx; w<width; w++ )

{
pPixel = pColorTable + (*pIdx)*3;
if (*pIdx==idx_trs)

{
//if( 32 == ddsd.ddpfPixelFormat.dwRGBBitCount )
// pDstData32[w] = 0;
//else
// pDstData16[w] = 0;
}
else

{

DWORD m_nRShiftL = 0; DWORD m_nRShiftR = 0;
DWORD m_nGShiftL = 0; DWORD m_nGShiftR = 0;
DWORD m_nBShiftL = 0; DWORD m_nBShiftR = 0;
DWORD m_nAShiftL = 0; DWORD m_nAShiftR = 0;

DWORD dr = ((DWORD(pPixel[0])>>(m_nRShiftL))<<m_nRShiftR);
DWORD dg = ((DWORD(pPixel[1])>>(m_nGShiftL))<<8);
DWORD db = ((DWORD(pPixel[2])>>(m_nBShiftL))<<16);
DWORD da = ((0xff>>(m_nAShiftL))<<24);
pDstData32[w] = (DWORD)(dr+dg+db+da);
}
pIdx ++;
}
pBytes += lPitch;
}

m_pTexture[0]->UnlockRect(0);
return true;
}
如有任何疑問請留言。交流~~
posted @
2009-04-04 01:05 Only Soft 閱讀(827) |
評論 (0) |
編輯 收藏