最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

淺析如何截獲C#程序產(chǎn)生的日志

 更新時間:2022年11月25日 10:00:36   作者:一線碼農(nóng)  
這篇文章主要和大家一起來聊一聊如何截獲C#程序產(chǎn)生的日志,文中的示例代碼講解詳細(xì),具有一定的借鑒價值,感興趣的小伙伴可以學(xué)習(xí)一下

一:背景

1.講故事

前段時間分析了一個dump,一頓操作之后,我希望用外力來阻止程序內(nèi)部對某一個com組件的調(diào)用,對,就是想借助外力實現(xiàn),如果用 windbg 的話,可以說非常輕松,但現(xiàn)實情況比較復(fù)雜,客戶機沒有windbg,也不想加入任何的手工配置,希望全自動化來處理。

真的很無理哈。。。不過這種無理要求花點心思還是可以實現(xiàn)的,方法就是用代碼將應(yīng)用程序變成調(diào)試器 來實現(xiàn)自動化阻止,為了簡化操作,我們拿 C# 的 File.WriteAllText 來舉個例子,讓我的調(diào)試器來截獲它的 content。

2. 測試案例

為了方便講述,創(chuàng)建一個 WPF 程序,在 button 事件中用 File.WriteAllText 方法來寫日志,參考代碼如下:

    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            System.IO.File.WriteAllText("C:\\1.txt", DateTime.Now.ToString());
        }
    }

代碼非常簡單,點一下按鈕就寫一條時間日志,接下來分別用 WinDbg 和 自定義調(diào)試器 來截獲這個時間。

二:WinDbg 下的實現(xiàn)

1. 實現(xiàn)原理

要想截獲日志,需要知道這個鏈路的下游方法,比如:kernel32!WriteFile,msdn 上的定義如下:

BOOL WriteFile(
  [in]                HANDLE       hFile,
  [in]                LPCVOID      lpBuffer,
  [in]                DWORD        nNumberOfBytesToWrite,
  [out, optional]     LPDWORD      lpNumberOfBytesWritten,
  [in, out, optional] LPOVERLAPPED lpOverlapped
);

其中 lpBuffer 存放的就是 content 信息, nNumberOfBytesToWrite 存放的是長度,有了這些基礎(chǔ),就可以通過 bp 下斷點了。

0:007> bp kernel32!WriteFile

0:007> g
Breakpoint 0 hit
eax=0126a4e8 ebx=00000000 ecx=000004a0 edx=76663510 esi=0320eb6c edi=010feaa8
eip=76663510 esp=010fea24 ebp=010fea90 iopl=0         nv up ei pl nz na po nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00200202
KERNEL32!WriteFile:
76663510 ff2558106c76    jmp     dword ptr [KERNEL32!_imp__WriteFile (766c1058)] ds:002b:766c1058={KERNELBASE!WriteFile (75ebd760)}

0:000> kb 3
 # ChildEBP RetAddr      Args to Child              
00 010fea90 6a829fef     00000000 010feaa8 00000013 KERNEL32!WriteFile
01 010feab8 6a829f2c     010fead4 00000000 00000013 mscorlib_ni!System.IO.FileStream.WriteFileNative+0x6f
02 010feae0 6a829ec5     00000013 00000000 0320d69c mscorlib_ni!System.IO.FileStream.WriteCore+0x3c 

因為 kernel32!WriteFile 用的是 stdcall 協(xié)定,所以 lpBuffer 變量在 esp+0x8 的位置, nNumberOfBytesToWrite 變量在 esp+0xc 的位置。

0:000> da poi(esp+8)
0320eb6c  "2022/11/24 17:25:39"

0:000> dp esp+0xc L1
010fea30  00000013

0:000> ? poi(esp+0xc)
Evaluate expression: 19 = 00000013

從卦中看,content 和 length 都出來了,非常完美,接下來看下如何自定義實現(xiàn)調(diào)試器。

三:自己實現(xiàn)一個調(diào)試器

1. 技術(shù)原理

要想自定義實現(xiàn),需要打通這三塊。

如何給 kernel32!WriteFile 下 bp 斷點

bp 的原理其實就是 int 3 ,簡而言之就是 windbg 會將 kernel32!WriteFile 指令的首字節(jié)修改成機器碼 0xcc,命中之后又將 0xcc 撤銷掉。這一串邏輯是 windbg 內(nèi)部自己實現(xiàn)的,接下來我們驗證下,將首字節(jié)直接改成 0xcc 。

0:011> x kernel32!WriteFile
76663510          KERNEL32!WriteFile (_WriteFile@20)
0:011> db 76663510 L1
76663510  ff                                               .
0:011> eb 76663510 cc
0:011> db 76663510 L1
76663510  cc                                               .

從卦中看已修改成功,接下來直接點擊 WPF 窗體的 button 按鈕就會直接命中這里的 int 3 實現(xiàn)中斷。

到了這一步后,可以在程序中使用 WriteProcessMemory 恢復(fù) WriteFile 原始字節(jié)為 ff

如何讓 int 3 中斷給程序

剛才看到的是中斷給WinDbg,那怎么中斷給程序呢? 其實 Win32 API 中有一個叫 DebugActiveProcess 函數(shù)可以讓宿主程序充當(dāng)調(diào)試器,mdsn 中的描述如下:

如何讀寫 wpf 的內(nèi)存和寄存器

只要獲取到了 wpf 程序的進程和線程句柄,可以用 WriteProcessMemory 和 ReadProcessMemory 讀寫內(nèi)存,用 GetThreadContext 和 SetThreadContext 讀寫寄存器。

2. 代碼實現(xiàn)

思路和技術(shù)都搞清楚后,代碼落地就非常簡單了,參考如下:

// HookDebug.cpp : This file contains the 'main' function. Program execution begins and ends there.
//

#include <iostream>
#include <Windows.h>

LPVOID writefile_addr = NULL;
CREATE_PROCESS_DEBUG_INFO cpdi;
BYTE int3 = 0xCC;
BYTE ff = 0;

BOOL OnCreateProcessDebugEvent(LPDEBUG_EVENT pde) {

	writefile_addr = GetProcAddress(GetModuleHandle(L"kernel32.dll"), "WriteFile");

	memcpy(&cpdi, &pde->u.CreateProcessInfo, sizeof(CREATE_PROCESS_DEBUG_INFO));

	ReadProcessMemory(cpdi.hProcess, writefile_addr, &ff, sizeof(BYTE), NULL);
	WriteProcessMemory(cpdi.hProcess, writefile_addr, &int3, sizeof(BYTE), NULL);

	return TRUE;
}

BOOL OnExceptionDebugEvent(LPDEBUG_EVENT pde) {

	CONTEXT ctx;
	PBYTE lpBuffer = NULL;
	DWORD lpBufferStart, nNumberOfBytesToWrite;

	PEXCEPTION_RECORD pr = &pde->u.Exception.ExceptionRecord;

	//int3 斷點
	if (pr->ExceptionCode == EXCEPTION_BREAKPOINT && writefile_addr == pr->ExceptionAddress) {

		//1. unhook,恢復(fù) writefile 的
		WriteProcessMemory(cpdi.hProcess, writefile_addr, &ff, sizeof(BYTE), NULL);

		//2. 獲取上下文
		ctx.ContextFlags = CONTEXT_ALL;
		GetThreadContext(cpdi.hThread, &ctx);

		//3. 獲取 WriteFile 寫入的內(nèi)容
		ReadProcessMemory(cpdi.hProcess, (PVOID)(ctx.Esp + 0x8), &lpBufferStart, sizeof(DWORD), NULL);
		ReadProcessMemory(cpdi.hProcess, (PVOID)(ctx.Esp + 0xc), &nNumberOfBytesToWrite, sizeof(DWORD), NULL);

		//4. 分配緩沖區(qū)
		lpBuffer = (PBYTE)calloc(nNumberOfBytesToWrite + 1, sizeof(BYTE));

		//5. copy 數(shù)據(jù)到緩沖區(qū)中
		ReadProcessMemory(cpdi.hProcess, (LPVOID)lpBufferStart, lpBuffer, nNumberOfBytesToWrite, NULL);

		printf("截獲的內(nèi)容: %s \n", lpBuffer);

		//6. 重新修改 eip ,指向 writefile 開頭,寫回到線程上下文中
		ctx.Eip = (DWORD)writefile_addr;
		SetThreadContext(cpdi.hThread, &ctx);

		//7. 繼續(xù)執(zhí)行
		ContinueDebugEvent(pde->dwProcessId, pde->dwThreadId, DBG_CONTINUE);

		Sleep(0);

		//8. 重新 hook
		WriteProcessMemory(cpdi.hProcess, writefile_addr, &int3, sizeof(BYTE), NULL);

		return TRUE;
	}

	return FALSE;
}

void loop() {

	DEBUG_EVENT de;

	while (WaitForDebugEvent(&de, INFINITE))
	{
		//注入事件
		if (de.dwDebugEventCode == CREATE_PROCESS_DEBUG_EVENT) {
			OnCreateProcessDebugEvent(&de);
		}

		//異常事件
		if (de.dwDebugEventCode == EXCEPTION_DEBUG_EVENT) {
			if (OnExceptionDebugEvent(&de)) continue;
		}

		ContinueDebugEvent(de.dwProcessId, de.dwThreadId, DBG_CONTINUE);
	}
}

int main()
{
	//程序日志
	DWORD dwPID = 23264;

	if (!DebugActiveProcess(dwPID)) {
		printf("fail");
		return 1;
	}

	loop();

	return 0;
}

代碼中的 dwPID 是 WPF 程序的 PID,指定好之后把程序跑起來,點擊 button 按鈕觀察,截圖如下,非常完美。

三:總結(jié)

在無法安裝 windbg 的受限環(huán)境下,部署 HookDebug.exe 就是我們的另一種選擇,而且完全自動化攔截,基本實現(xiàn)無人工干預(yù)。

到此這篇關(guān)于淺析如何截獲C#程序產(chǎn)生的日志的文章就介紹到這了,更多相關(guān)C#截獲程序產(chǎn)生日志內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • C#實現(xiàn)一個Word保護性模板文件

    C#實現(xiàn)一個Word保護性模板文件

    這篇文章主要為大家詳細(xì)介紹了C#如何實現(xiàn)一個Word保護性模板文件,文中的示例代碼講解詳細(xì),具有一定的借鑒價值,需要的小伙伴可以參考一下
    2024-01-01
  • 基于C#動手實現(xiàn)網(wǎng)絡(luò)服務(wù)器Web Server

    基于C#動手實現(xiàn)網(wǎng)絡(luò)服務(wù)器Web Server

    這篇文章主要為大家詳細(xì)介紹了基于C#動手實現(xiàn)網(wǎng)絡(luò)服務(wù)器Web Server,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-10-10
  • 基于動態(tài)修改App.Config與web.Config的使用詳解

    基于動態(tài)修改App.Config與web.Config的使用詳解

    本篇文章是對動態(tài)修改App.Config與web.Config的使用進行了詳細(xì)的分析介紹,需要的朋友參考下
    2013-05-05
  • C#使用LINQ查詢操作符實例代碼(二)

    C#使用LINQ查詢操作符實例代碼(二)

    這篇文章介紹了C#使用LINQ查詢操作符的方法,文中通過示例代碼介紹的非常詳細(xì)。對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-06-06
  • C#中的三種定時計時器Timer用法介紹

    C#中的三種定時計時器Timer用法介紹

    這篇文章介紹了C#中的三種定時計時器Timer的用法,文中通過示例代碼介紹的非常詳細(xì)。對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-03-03
  • C#中參數(shù)個數(shù)可變的方法實例分析

    C#中參數(shù)個數(shù)可變的方法實例分析

    這篇文章主要介紹了C#中參數(shù)個數(shù)可變的方法,以一個簡單實例分析了C#中參數(shù)個數(shù)可變的方法,主要是使用params關(guān)鍵字來實現(xiàn)的,是C#編程中比較實用的技巧,需要的朋友可以參考下
    2014-11-11
  • richtextbox控件插入鏈接代碼分享

    richtextbox控件插入鏈接代碼分享

    richtextbox控件插入鏈接,暫時使用這個來解決鏈接的中文文本顯示
    2013-12-12
  • C# HTTP認(rèn)證方式詳解與代碼實現(xiàn)

    C# HTTP認(rèn)證方式詳解與代碼實現(xiàn)

    在C#中,HTTP認(rèn)證是客戶端與服務(wù)器之間進行身份驗證的一種機制,常見的HTTP認(rèn)證方式包括:Basic認(rèn)證、Digest認(rèn)證、OAuth、Bearer Token等,下面我們將從工作原理、優(yōu)缺點對比、代碼實現(xiàn)、案例實戰(zhàn)四個方面詳細(xì)介紹這些認(rèn)證方式,需要的朋友可以參考下
    2025-03-03
  • C#實現(xiàn)自定義動畫鼠標(biāo)的示例詳解

    C#實現(xiàn)自定義動畫鼠標(biāo)的示例詳解

    這篇文章主要為大家詳細(xì)介紹了如何利用C#實現(xiàn)自定義動畫鼠標(biāo)效果,文中的示例代碼講解詳細(xì),對我們學(xué)習(xí)C#有一定的幫助,感興趣的小伙伴可以跟隨小編一起了解一下
    2022-12-12
  • Unity向量按照某一點進行旋轉(zhuǎn)

    Unity向量按照某一點進行旋轉(zhuǎn)

    這篇文章主要為大家詳細(xì)介紹了Unity向量按照某一點進行旋轉(zhuǎn),文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-01-01

最新評論

甘孜县| 资源县| 秦皇岛市| 湖南省| 广昌县| 肃北| 顺平县| 潍坊市| 周口市| 罗甸县| 邢台县| 育儿| 平罗县| 靖江市| 开化县| 公主岭市| 泸定县| 威远县| 湛江市| 昌邑市| 武强县| 崇文区| 德昌县| 登封市| 丰城市| 呼和浩特市| 百色市| 朝阳区| 峡江县| 南昌县| 水城县| 黄大仙区| 那曲县| 瑞金市| 通山县| 山西省| 东安县| 遵化市| 闽侯县| 金川县| 波密县|