성태의 닷넷 이야기
홈 주인
모아 놓은 자료
프로그래밍
질문/답변
사용자 관리
사용자
메뉴
아티클
외부 아티클
유용한 코드
온라인 기능
MathJax 입력기
최근 덧글
[정성태] Reordering on an Alpha processor ;...
[정성태] 공유 감사합니다. ^^ 참고로, WPF에서 WindowsF...
[Tom Lee] 답변 감사합니다. 나름의 해결책 연구해보고 여기에도 공유해봅니다...
[정성태] 아래의 글을 보면, MoveWindow 하면 될 듯한데요. ^^...
[Tom Lee] 안녕하세요 올려주신 글 참고하여 WPF 어플리케이션 안에 Uni...
[정성태] A graphical depiction of the steps ...
[정성태] 질문을 주셔서 출판사 측에 문의를 했습니다. 약 한 달 정도 후...
[Thorondor
] @정성태 개인 블로그인데도 거의 커뮤니티 급 인 것 같아요. 요...
[정성태] Roll A Lisp In C - Reading ; https...
[정성태] Java - How to use the Foreign Funct...
글쓰기
제목
이름
암호
전자우편
HTML
홈페이지
유형
제니퍼 .NET
닷넷
COM 개체 관련
스크립트
VC++
VS.NET IDE
Windows
Team Foundation Server
디버깅 기술
오류 유형
개발 환경 구성
웹
기타
Linux
Java
DDK
Math
Phone
Graphics
사물인터넷
부모글 보이기/감추기
내용
<div style='display: inline'> <h1 style='font-family: Malgun Gothic, Consolas; font-size: 20pt; color: #006699; text-align: center; font-weight: bold'>C# - 커널 구조체의 Offset 값을 하드 코딩하지 않고 사용하는 방법</h1> <p> 물론, 지난 글에 설명한 cdb.exe 등을 이용해 커널 구조체를 출력하면,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > cdb.exe를 이용해 (ntdll.dll 등에 정의된) 커널 구조체 출력하는 방법 ; <a target='tab' href='https://www.sysnet.pe.kr/2/0/12092'>http://www.sysnet.pe.kr/2/0/12092</a> </pre> <br /> 해당 결과를 파싱해 해결할 수 있습니다. 또는, dbgeng.dll을 이용해 직접 제작한 디버거와 함께,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > C# - DbgEng.dll을 이용한 간단한 디버거 제작 ; <a target='tab' href='http://www.sysnet.pe.kr/2/0/12096'>http://www.sysnet.pe.kr/2/0/12096</a> </pre> <br /> PDB 심벌 파일을 다운로드하는 코드를 곁들이면,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > C# - 코드를 통해 PDB 심벌 파일 다운로드 방법 ; <a target='tab' href='http://www.sysnet.pe.kr/2/0/12094'>http://www.sysnet.pe.kr/2/0/12094</a> </pre> <br /> cdb.exe 없이도 이 문제를 해결할 수 있습니다. (필요한 라이브러리를 nuget에 올려두었으니) 대략 다음과 같은 식으로 작성하면 되겠지요. ^^<br /> <br /> <pre style='height: 400px; margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > <span style='color: blue; font-weight: bold'>/* Install-Package <a target='tab' href='https://www.nuget.org/packages/WindowsPE/'>WindowsPE</a> Install-Package <a target='tab' href='https://www.nuget.org/packages/SimpleDebugger/'>SimpleDebugger</a> */</span> using Microsoft.Diagnostics.Runtime.Interop; using SimpleDebugger; using System; using System.Diagnostics; using System.IO; using WindowsPE; namespace ConsoleApp1 { class Program { static void Main(string[] args) { string rootPathToSave = Path.Combine(Environment.CurrentDirectory, "sym"); using (UserDebugger debugger = new UserDebugger()) { debugger.SetOutputText(false); ProcessStartInfo psi = new ProcessStartInfo(); psi.FileName = "DummyApp.exe"; psi.UseShellExecute = false; psi.WindowStyle = ProcessWindowStyle.Hidden; psi.CreateNoWindow = true; Process child = Process.Start(psi); bool attached = false; try { DownloadPdb(child, rootPathToSave); debugger.ModuleLoaded += (ModuleInfo modInfo) => { RunDTSetCommand(debugger, rootPathToSave); debugger.SetOutputText(false); debugger.Execute(DEBUG_OUTCTL.IGNORE, "q", DEBUG_EXECUTE.NOT_LOGGED); }; if (debugger.AttachTo(child.Id) == false) { Console.WriteLine("Failed to attach"); return; } attached = true; debugger.WaitForEvent(); } finally { if (attached == true) { debugger.Detach(); } try { child.Kill(); } catch { } } } } private static void RunDTSetCommand(UserDebugger debugger, string rootPathToSave) { { string cmd = ".sympath \"" + rootPathToSave + "\""; int result = debugger.Execute(DEBUG_OUTCTL.IGNORE, cmd, DEBUG_EXECUTE.NOT_LOGGED); if (result != (int)HResult.S_OK) { Console.WriteLine("failed to run command: " + cmd); return; } } { string cmd = ".reload /s /f ntdll.dll"; int result = debugger.Execute(DEBUG_OUTCTL.IGNORE, cmd, DEBUG_EXECUTE.NOT_LOGGED); if (result != (int)HResult.S_OK) { Console.WriteLine("failed to run command: " + cmd); return; } } debugger.SetOutputText(true); { string cmd = "dt ntdll!_PEB"; int result = debugger.Execute(cmd); if (result != (int)HResult.S_OK) { Console.WriteLine("failed to run command: " + cmd); return; } } } private static void DownloadPdb(Process child, string rootPathToSave) { foreach (ProcessModule module in child.Modules) { if (module.FileName.EndsWith("ntdll.dll", StringComparison.OrdinalIgnoreCase) == true) { string modulePath = module.FileName; PEImage pe = PEImage.ReadFromFile(modulePath); DownloadPdb(modulePath, rootPathToSave); return; } } } private static void DownloadPdb(string modulePath, string rootPathToSave) { if (File.Exists(modulePath) == false) { Console.WriteLine("NOT Found: " + modulePath); return; } PEImage pe = PEImage.ReadFromFile(modulePath); if (pe == null) { Console.WriteLine("Failed to read images"); return; } Uri baseUri = new Uri("https://msdl.microsoft.com/download/symbols/"); foreach (CodeViewRSDS codeView in pe.EnumerateCodeViewDebugInfo()) { if (string.IsNullOrEmpty(codeView.PdbFileName) == true) { continue; } string pdbFileName = codeView.PdbFileName; if (Path.IsPathRooted(codeView.PdbFileName) == true) { pdbFileName = Path.GetFileName(codeView.PdbFileName); } string localPath = Path.Combine(rootPathToSave, pdbFileName); string localFolder = Path.GetDirectoryName(localPath); if (Directory.Exists(localFolder) == false) { try { Directory.CreateDirectory(localFolder); } catch (DirectoryNotFoundException) { Console.WriteLine("NOT Found on local: " + codeView.PdbLocalPath); continue; } } if (File.Exists(localPath) == true) { continue; } if (CopyPdbFromLocal(modulePath, codeView.PdbFileName, localPath) == true) { continue; } Uri target = new Uri(baseUri, codeView.PdbUriPath); Uri pdbLocation = GetPdbLocation(target); if (pdbLocation == null) { string underscorePath = ProbeWithUnderscore(target.AbsoluteUri); pdbLocation = GetPdbLocation(new Uri(underscorePath)); } if (pdbLocation != null) { DownloadPdbFile(pdbLocation, localPath); } else { Console.WriteLine("Not Found on symbol server: " + codeView.PdbFileName); } } } private static bool CopyPdbFromLocal(string modulePath, string pdbFileName, string localTargetPath) { if (File.Exists(pdbFileName) == true) { File.Copy(pdbFileName, localTargetPath); return File.Exists(localTargetPath); } string fileName = Path.GetFileName(pdbFileName); string pdbPath = Path.Combine(Environment.CurrentDirectory, fileName); if (File.Exists(pdbPath) == true) { File.Copy(pdbPath, localTargetPath); return File.Exists(localTargetPath); } pdbPath = Path.ChangeExtension(modulePath, ".pdb"); if (File.Exists(pdbPath) == true) { File.Copy(pdbPath, localTargetPath); return File.Exists(localTargetPath); } return false; } private static string ProbeWithUnderscore(string path) { path = path.Remove(path.Length - 1); path = path.Insert(path.Length, "_"); return path; } private static void DownloadPdbFile(Uri target, string pathToSave) { System.Net.HttpWebRequest req = System.Net.WebRequest.Create(target) as System.Net.HttpWebRequest; using (System.Net.HttpWebResponse resp = req.GetResponse() as System.Net.HttpWebResponse) using (FileStream fs = new FileStream(pathToSave, FileMode.CreateNew, FileAccess.Write, FileShare.None)) using (BinaryWriter bw = new BinaryWriter(fs)) { BinaryReader reader = new BinaryReader(resp.GetResponseStream()); long contentLength = resp.ContentLength; while (contentLength > 0) { byte[] buffer = new byte[4096]; int readBytes = reader.Read(buffer, 0, buffer.Length); bw.Write(buffer, 0, readBytes); contentLength -= readBytes; } } } private static Uri GetPdbLocation(Uri target) { System.Net.HttpWebRequest req = System.Net.WebRequest.Create(target) as System.Net.HttpWebRequest; req.Method = "HEAD"; try { using (System.Net.HttpWebResponse resp = req.GetResponse() as System.Net.HttpWebResponse) { return resp.ResponseUri; } } catch (System.Net.WebException) { return null; } } } } </pre> <br /> 위의 코드를 Windows 10 1909 x64에서 실행하면 다음과 같은 출력을 얻을 수 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > C:\temp> ConsoleApp1.exe +0x000 InheritedAddressSpace : UChar +0x001 ReadImageFileExecOptions : UChar +0x002 BeingDebugged : UChar +0x003 BitField : UChar ...[생략]... +0x7c0 LeapSecondFlags : Uint4B +0x7c0 SixtySecondEnabled : Pos 0, 1 Bit +0x7c0 Reserved : Pos 1, 31 Bits +0x7c4 NtGlobalFlag2 : Uint4B </pre> <br /> 마찬가지로 Windows Server 2008 x86에서 실행하면 다음과 같이 결과가 바뀌므로,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > C:\temp> ConsoleApp1.exe +0x000 InheritedAddressSpace : UChar +0x001 ReadImageFileExecOptions : UChar +0x002 BeingDebugged : UChar +0x003 BitField : UChar ...[생략]... +0x22c FlsHighIndex : Uint4B +0x230 WerRegistrationData : Ptr32 Void +0x234 WerShipAssertPtr : Ptr32 Void </pre> <br /> 출력을 잘 이용하면 지겨운 offset 값 하드 코딩을 없앨 수 있겠습니다. ^^<br /> <br /> <hr style='width: 50%' /><br /> <br /> 기왕 하는 김에, 위의 결과를 종합해 간단하게 라이브러리로 만들어 nuget에 올렸습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > KernelStructOffset ; <a target='tab' href='https://www.nuget.org/packages/KernelStructOffset/'>https://www.nuget.org/packages/KernelStructOffset/</a> 소스 코드 ; <a target='tab' href='https://github.com/stjeong/DotNetSamples/tree/master/WinConsole/Debugger'>https://github.com/stjeong/DotNetSamples/tree/master/WinConsole/Debugger</a> </pre> <br /> 따라서 패키지 추가 후,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > Install-Package KernelStructOffset </pre> <br /> 다음과 같이 코딩을 완료할 수 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; class Program { static void Main(string[] args) { <span style='color: blue; font-weight: bold'>var dict = DbgOffset.Get("_PEB", "ntdll.dll");</span> <span style='color: blue; font-weight: bold'>int offset = dict["Ldr"];</span> Console.WriteLine("Ldr: " + offset + "(0x" + offset.ToString("x") + ")"); } } </pre> </p><br /> <br /><hr /><span style='color: Maroon'>[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]</span> </div>
첨부파일
스팸 방지용 인증 번호
1191
(왼쪽의 숫자를 입력해야 합니다.)