Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • SEARCH
  • Home
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 7023999
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: May 27, 20262026-05-27T23:46:58+00:00 2026-05-27T23:46:58+00:00

Background: I’ve written a multi-threaded application in Win32, which I start from C# code

  • 0

Background:

I’ve written a multi-threaded application in Win32, which I start from C# code using Process class from System.Diagnostics namespace.

Now, in the C# code, I want to get the name/symbol of the start address of each thread created in the Win32 application so that I could log thread related information, such as CPU usage, to database. Basically, C# code starts multiple instances of the Win32 Application, monitors them, kills if needed, and then logs info/error/exceptions/reason/etc to database.

For this purpose, I’ve wrapped two Win32 API viz. SymInitialize and SymFromAddr in programmer-friendly API written by myself, as listed below:

extern "C"
{
    //wraps SymInitialize
    DllExport bool initialize_handler(HANDLE hModue);

    //wraps SymFromAddr
    DllExport bool get_function_symbol(HANDLE hModule, //in
                                       void *address,  //in
                                       char *name);    //out
}

And then call these API from C# code, using pinvoke. But it does not work and GetLastError gives 126 error code which means:

The specified module could not be found

I’m passing Process.Handle as hModule to both functions; initialize_handler seems to work, but get_function_symbol does not; it gives the above error. I’m not sure if I’m passing the correct handle. I tried passing the following handles:

Process.MainWindowHandle
Process.MainModule.BaseAddress

Both fail at the first step itself (i.e when calling initialize_handler). I’m passing Process.Threads[i].StartAddress as second argument, and that seems to be cause of the failure as ProcessThread.StartAddress seems to be the address of RtlUserThreadStart function, not the address of the start function specific to the application. The MSDN says about it:

Every Windows thread actually begins execution in a system-supplied function, not the application-supplied function. The starting address for the primary thread is, therefore, the same (as it represents the address of the system-supplied function) for every Windows process in the system. However, the StartAddress property allows you to get the starting function address that is specific to your application.

But it doesn’t say how to get the startinbg function address specific to the application, using ProcessThread.StartAddress.

Question:

My problem boils to getting the start address of win32 thread from another application (written in C#), as once I get it, I will get the name as well, using the above mentioned APIs. So how to get the start address?


I tested my symbol lookup API from C++ code. It works fine to resolve the address to a symbol, if given the correct address to start with.

Here is my p/invoke declarations:

[DllImport("UnmanagedSymbols.dll", SetLastError = true, CallingConvention= CallingConvention.Cdecl)]
static extern bool initialize_handler(IntPtr hModule);

[DllImport("UnmanagedSymbols.dll", SetLastError = true, CallingConvention = CallingConvention.Cdecl)]
static extern bool get_function_symbol(IntPtr hModule, IntPtr address, StringBuilder name);
  • 1 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. Editorial Team
    Editorial Team
    2026-05-27T23:46:59+00:00Added an answer on May 27, 2026 at 11:46 pm

    The key is to call the NtQueryInformationThread function. This is not a completely “official” function (possibly undocumented in the past?), but the documentation suggests no alternative for getting the start address of a thread.

    I’ve wrapped it up into a .NET-friendly call that takes a thread ID and returns the start address as IntPtr. This code has been tested in x86 and x64 mode, and in the latter it was tested on both a 32-bit and a 64-bit target process.

    One thing I did not test was running this with low privileges; I would expect that this code requires the caller to have the SeDebugPrivilege.

    using System;
    using System.ComponentModel;
    using System.Diagnostics;
    using System.Linq;
    using System.Runtime.InteropServices;
    
    class Program
    {
        static void Main(string[] args)
        {
            PrintProcessThreads(Process.GetCurrentProcess().Id);
            PrintProcessThreads(4156); // some other random process on my system
            Console.WriteLine("Press Enter to exit.");
            Console.ReadLine();
        }
    
        static void PrintProcessThreads(int processId)
        {
            Console.WriteLine(string.Format("Process Id: {0:X4}", processId));
            var threads = Process.GetProcessById(processId).Threads.OfType<ProcessThread>();
            foreach (var pt in threads)
                Console.WriteLine("  Thread Id: {0:X4}, Start Address: {1:X16}",
                                  pt.Id, (ulong) GetThreadStartAddress(pt.Id));
        }
    
        static IntPtr GetThreadStartAddress(int threadId)
        {
            var hThread = OpenThread(ThreadAccess.QueryInformation, false, threadId);
            if (hThread == IntPtr.Zero)
                throw new Win32Exception();
            var buf = Marshal.AllocHGlobal(IntPtr.Size);
            try
            {
                var result = NtQueryInformationThread(hThread,
                                 ThreadInfoClass.ThreadQuerySetWin32StartAddress,
                                 buf, IntPtr.Size, IntPtr.Zero);
                if (result != 0)
                    throw new Win32Exception(string.Format("NtQueryInformationThread failed; NTSTATUS = {0:X8}", result));
                return Marshal.ReadIntPtr(buf);
            }
            finally
            {
                CloseHandle(hThread);
                Marshal.FreeHGlobal(buf);
            }
        }
    
        [DllImport("ntdll.dll", SetLastError = true)]
        static extern int NtQueryInformationThread(
            IntPtr threadHandle,
            ThreadInfoClass threadInformationClass,
            IntPtr threadInformation,
            int threadInformationLength,
            IntPtr returnLengthPtr);
    
        [DllImport("kernel32.dll", SetLastError = true)]
        static extern IntPtr OpenThread(ThreadAccess dwDesiredAccess, bool bInheritHandle, int dwThreadId);
    
        [DllImport("kernel32.dll", SetLastError = true)]
        static extern bool CloseHandle(IntPtr hObject);
    
        [Flags]
        public enum ThreadAccess : int
        {
            Terminate = 0x0001,
            SuspendResume = 0x0002,
            GetContext = 0x0008,
            SetContext = 0x0010,
            SetInformation = 0x0020,
            QueryInformation = 0x0040,
            SetThreadToken = 0x0080,
            Impersonate = 0x0100,
            DirectImpersonation = 0x0200
        }
    
        public enum ThreadInfoClass : int
        {
            ThreadQuerySetWin32StartAddress = 9
        }
    }
    

    Output on my system:

    Process Id: 2168    (this is a 64-bit process)
      Thread Id: 1C80, Start Address: 0000000001090000
      Thread Id: 210C, Start Address: 000007FEEE8806D4
      Thread Id: 24BC, Start Address: 000007FEEE80A74C
      Thread Id: 12F4, Start Address: 0000000076D2AEC0
    Process Id: 103C    (this is a 32-bit process)
      Thread Id: 2510, Start Address: 0000000000FEA253
      Thread Id: 0A0C, Start Address: 0000000076F341F3
      Thread Id: 2438, Start Address: 0000000076F36679
      Thread Id: 2514, Start Address: 0000000000F96CFD
      Thread Id: 2694, Start Address: 00000000025CCCE6
    

    apart from the stuff in parentheses since that requires extra P/Invoke’s.


    Regarding SymFromAddress “module not found” error, I just wanted to mention that one needs to call SymInitialize with fInvadeProcess = true OR load the module manually, as documented on MSDN.

    I know you say this isn’t the case in your situation, but I’ll leave this in for the benefit of anyone who finds this question via those keywords.

    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Related Questions

Background: I want to check-out the source code from Cliche , which is stored
Background: Some time ago, I built a system for recording and categorizing application crashes
Background I have a ror application which is continuously recording and showing on a
BACKGROUND: Co-worker Adam has been using Google refine to process database downloads with much
Background I have written a test suite in mstest which has a template XML.
Background: At my company we are developing a bunch applications that are using the
Background I am writing and using a very simple CGI-based (Perl) content management tool
Background I work for a large organization which has thousands of MS Access applications
Background I am writing code in VS 2010, .NET 4, C#. Also, in case
Background: I've wrote a small library that is able to create asp.net controls from

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.