0

In a micro-controller programmed using C/C++ all the addresses are known before the program starts. I can use an elf file that is generated when compiling to find those with gdb, for example:

gdb "elfFile.elf" -ex "print &variableName" -ex quit

This is useful to get variables in real-time by asking the micro-controller for a variable address from an external tool that can be used to log and plot data. The tool gets the variable address from the elf file and then just asks the micro-controller to read the data at address &variableName for n bytes.

I have ported some of the micro-controller code to Windows for testing purposes and it is running correctly. I would like to add the log functionality and for this purpose I need to be able to get a variable address programmatically from a running exe file. The address of variables is not known until the program starts in Windows (perhaps the offset is known though). I am using Visual Studio Express 2017 and I intend to get addresses of the program I compile myself, not any program from outside. From inside Visual Studio I can see any variable with the debugger so I hope there's gotta be a debugger exe file I can call from outside and attach to my program and read the variable addresses in a similar fashion as I did with gdb.

Any help? Thank you

Carlos
  • 105
  • 2
  • 14
  • Have the Windows program dump all relevant addresses to a text file or such, first thing it does? Emulating a microcontroller in Windows is mostly just quackery no matter how you put it. In particular, Windows has non-existent real-time behavior. – Lundin May 14 '20 at 07:52

1 Answers1

1

You could inject a dll with CreateRemoteProcess, and read the variable address there.

But you're looking for a program called OllyDbg.

Also, you could download and install MinGW & msys, then you can build GDB for Windows from source. But then you have to use MinGW on Windows to compile the program. (Mingw creates native Win32/Win64 programs - no need for Cygwin)

I don't have the C-Sources anymore for CreateRemoteThread, but I can give you the C# source:

// Inject(DLL_NAME, "Engine");
void Inject(string strDLLtoInject, string strEngine) 
{
    CheckIfDebugger();
    //String pszLibFileRemote = Application.StartupPath + "\\"+ strDLLtoInject;            
    //String pszLibFileRemote = Application.StartupPath + "\\"+ strDLLtoInject;            
    //String strPathOfSharedObjectToInject = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location) + System.IO.Path.DirectorySeparatorChar + strDLLtoInject;
    String strPathOfSharedObjectToInject = m_strTempPath + strDLLtoInject;

    //System.Windows.Forms.MessageBox.Show(strPathOfSharedObjectToInject);
    System.Diagnostics.Process[] TargetProcess = System.Diagnostics.Process.GetProcessesByName(strEngine);

    if (TargetProcess.Length > 0)
    {
        System.IntPtr pTargetProcess = WinAPI.OpenProcess(WinAPI.CREATE_THREAD_ACCESS, false, TargetProcess[0].Id);
        if (pTargetProcess != System.IntPtr.Zero)
        {
            CheckIfDebugger();
            int iLoadLibraryAaddress = WinAPI.GetProcAddress(WinAPI.GetModuleHandleA("Kernel32.dll"), "LoadLibraryA");
            if (iLoadLibraryAaddress != 0)
            {
                int iSharedObjectNameBufferSize = 1 + strPathOfSharedObjectToInject.Length;
                int iSharedObjectNameAddress = WinAPI.VirtualAllocEx(pTargetProcess, 0, iSharedObjectNameBufferSize, 4096, 4);

                if (iSharedObjectNameAddress != 0)
                {
                    CheckIfDebugger();
                    int iReturnValue = WinAPI.WriteProcessMemory(pTargetProcess, iSharedObjectNameAddress, strPathOfSharedObjectToInject, iSharedObjectNameBufferSize, 0);

                    if (iReturnValue != 0)
                        WinAPI.CreateRemoteThread(pTargetProcess, 0, 0, iLoadLibraryAaddress, iSharedObjectNameAddress, 0, 0);
                    else
                        MsgBox("WriteProcessMemory failed.", "Error");

                    CheckIfDebugger();
                } // End if (iSharedObjectNameAddress != null)
                else
                    MsgBox("VirtualAllocEx failed.", "Error");

            }// End if (iLoadLibraryAaddress != null)
            else
                MsgBox("GetProcAddress or GetModuleHandleA failed.", "Error");

            CheckIfDebugger();
            WinAPI.CloseHandle(pTargetProcess);
        } // End if (pTargetProcess != System.IntPtr.Zero)
        else
            MsgBox("OpenProcess failed.", "Error");

        CheckIfDebugger();
    } // End if (TargetProcess.Length > 0)
    else
        MsgBox("GetProcessesByName failed.", "Error");

    CheckIfDebugger();
} // End Sub Inject

Here's the WinAPI calls:

class WinAPI
{
    public const int CREATE_THREAD_ACCESS = 0x1F0FFF;


    [System.Runtime.InteropServices.DllImport("kernel32.dll")]
    public static extern IntPtr OpenProcess(int dwDesiredAccess, bool bInheritHandle, int dwProcessId);

    [System.Runtime.InteropServices.DllImport("Kernel32", EntryPoint = "GetModuleHandleA", ExactSpelling = true, CharSet = System.Runtime.InteropServices.CharSet.Ansi, SetLastError = true)]
    public static extern int GetModuleHandleA(string lpModuleName);

    [System.Runtime.InteropServices.DllImport("kernel32", ExactSpelling = true, CharSet = System.Runtime.InteropServices.CharSet.Ansi, SetLastError = true)]
    public static extern int GetProcAddress(int hModule, string lpProcName);

    [System.Runtime.InteropServices.DllImport("kernel32", ExactSpelling = true, CharSet = System.Runtime.InteropServices.CharSet.Ansi, SetLastError = true)]
    public static extern int VirtualAllocEx(System.IntPtr hProcess, int lpAddress, int dwSize, int flAllocationType, int flProtect);

    [System.Runtime.InteropServices.DllImport("kernel32", ExactSpelling = true, CharSet = System.Runtime.InteropServices.CharSet.Ansi, SetLastError = true)]
    public static extern int WriteProcessMemory(System.IntPtr hProcess, int lpBaseAddress, string lpBuffer, int nSize, int lpNumberOfBytesWritten);

    [System.Runtime.InteropServices.DllImport("kernel32", ExactSpelling = true, CharSet = System.Runtime.InteropServices.CharSet.Ansi, SetLastError = true)]
    public static extern int CreateRemoteThread(System.IntPtr hProcess, int lpThreadAttributes, int dwStackSize, int lpStartAddress, int lpParameter, int dwCreationFlags, int lpThreadId);

    [System.Runtime.InteropServices.DllImport("kernel32", EntryPoint = "CloseHandle")]
    public static extern int CloseHandle(System.IntPtr hObject);

    // http://www.pinvoke.net/default.aspx/kernel32/GetVersion.html
    [System.Runtime.InteropServices.DllImport("kernel32.dll")]
    public static extern uint GetVersion();

    [System.Runtime.InteropServices.DllImport("kernel32.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto, ExactSpelling = true)]
    internal static extern bool IsDebuggerPresent();


} // End class WinAPI
Stefan Steiger
  • 78,642
  • 66
  • 377
  • 442