Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ability to set initial directrory #2833

Open
Dwedit opened this issue Feb 11, 2022 · 15 comments
Open

Ability to set initial directrory #2833

Dwedit opened this issue Feb 11, 2022 · 15 comments
Labels
feature good first issue gui

Comments

@Dwedit
Copy link

@Dwedit Dwedit commented Feb 11, 2022

Feature type

Quality of life

Describe the feature

It seems that you can change the command line arguments using the File menu. But there is no way to do something similar to change the starting directory.

So far, the only way I found to change the starting directory was to restart X64dbg from the command line, explicitly passing in the command line and startup directory parameters.

So is there a way to simply add a second text box to the "Change Command Line" dialog box to specify the initial directory?

Using the "chd" command in the debugger does not affect the startup directory for the debugged application.

@Dwedit Dwedit added the feature label Feb 11, 2022
@mrexodia mrexodia added good first issue gui labels Feb 24, 2022
@mrexodia
Copy link
Member

@mrexodia mrexodia commented Feb 24, 2022

This came up in a discussion a while back too. There are currently two ways:

  1. Use x96dbg.exe (the launcher) to start your application from the directory you want
    • This has the issue of not remembering the working directory on restart
  2. Use the init command to specify the command line and working directory. This won't remember the working directory on restart either, but at least you can favorite the command.

I think it's a good idea to add functionality to change the working directory (similar to the command line), and then also handle saving the working directory in a similar way.

@rajkumarananthu
Copy link
Contributor

@rajkumarananthu rajkumarananthu commented Mar 6, 2022

Hi @mrexodia I am planning on attempting to implement this feature, below is the description of the possibility I am thinking:

  1. Add an action to change the initial directory to file menu.
  2. Get the absolute path from the user, which should be set as current folder.
  3. Set the current folder using current folder member in INIT_STRUCT using dbgcreatedebugthread.
  4. When using the run action or restart as admin, we will use this path to pass to ShellExecuteW() function as current working directory.

I didn't get the last part "saving the working directory". Can you please explain it and please let me know what you think of my approach. And also if possible can you assign this issue to me.

Thanks
Rajkumar Ananthu.

@mrexodia
Copy link
Member

@mrexodia mrexodia commented Mar 6, 2022

Thanks for picking this up! Check out the code related to the command line here: https://github.com/x64dbg/x64dbg/blob/development/src/dbg/commandline.cpp

The option changes the command line while the process is running (by modifying the UNICODE_STRING in the PEB). This is a bit more flexible and it makes it so you don’t have to worry about the CreateProcess call used to start the debuggee.

Perhaps you can start by implementing a command that sets the working directory, the GUI should only be a few lines from there.

@rajkumarananthu
Copy link
Contributor

@rajkumarananthu rajkumarananthu commented Mar 9, 2022

Hi @mrexodia , Thanks for the input, I went through the flow how the command line options are changed and I am using the same to change the CurrentDirectory for the executable.

I almost completed the process, but stuck at the point where you are capturing the command line arguments from instructions as follows:

ifdef _WIN64                                                                                       
    /*                                                                                              
    00007FFC5B91E3C8 | 48 8B 05 19 1D 0E 00     | mov rax,qword ptr ds:[7FFC5BA000E8]               
    00007FFC5B91E3CF | C3                       | ret                                     |         
    This is a relative offset then to get the symbol: next instruction of getmodulehandle (+7 bytes) + offset to symbol
    (the last 4 bytes of the instruction)                                                           
    */   
#else // x86
    /*                                                                                              
    750FE9CA | A1 CC DB 1A 75           | mov eax,dword ptr ds:[751ADBCC]         |                 
    750FE9CF | C3                       | ret                                     |                 
    */ 
#endif 

can you please guide me how to find current directory equivalents for these instructions?

Thanks
Rajkumar Ananthu.

@mrexodia
Copy link
Member

@mrexodia mrexodia commented Mar 9, 2022

You can find some relevant code here: https://github.com/sonicmouse/ProcCmdLine/blob/master/ProcessHelper.cpp#L66

This is just to get it, but to set it you modify the UNICODE_STRING to point to your newly allocated buffer.

@rajkumarananthu
Copy link
Contributor

@rajkumarananthu rajkumarananthu commented Mar 10, 2022

Hi @mrexodia , thanks for the pointer, I think that pointer given by you will work for getting the initial directory that is set(through writing to PEB location), but my question is while setting the initial directory. If you see for changing the command line:

if(!fixgetcommandlinesbase(mem, mem + new_command_line.MaximumLength, cmd_line_error))

Here we are running a function called fixgetcommandlinesbase(), this is changing the buffers some other place also using kernelbase:GetCommandLineA & kernelbase:GetCommandLineP and patchcmdline() function.
static bool patchcmdline(duint getcommandline, duint new_command_line, cmdline_error_t* cmd_line_error)

I similarly used kernelbase:GetCurrentDirectoryA & kernelbase:GetCurrentDirectoryP, but for implementing the functionality of the patchinitdir, I am seeing the following mnemonic( 48 89 5C 24 18 | mov qword ptr ss:[rsp+18],rbx ).
Which is using stack segment, instead of data segment pointer in the case of Command Line, I am not sure how to proceed after this to implement the functionality of patchinitdir(). That is where I got stuck for now.

Please guide me if I am on wrong track or anything wrong in my understanding so far.

Thanks,
Rajkumar Ananthu

PS: The getinitdir is working fine for me(because PEB write is happening). The setting is what I am facing an issue, and I am using small C++ executable which checks for the the existence of a file in some directory, and I want to make that particular directory as initial directory.

@mrexodia
Copy link
Member

@mrexodia mrexodia commented Mar 10, 2022

Hm, I think you would have to reverse engineer and see what SetCurrentDirectoryW is doing. Likely there is also some kind of handle to the directory somewhere that needs to be changed...

@Dwedit
Copy link
Author

@Dwedit Dwedit commented Mar 10, 2022

Is this issue suddenly about changing working directory at runtime? I thought this was about changing working directory at startup time. It's a parameter of CreateProcessW.

@mrexodia
Copy link
Member

@mrexodia mrexodia commented Mar 10, 2022

@Dwedit
Copy link
Author

@Dwedit Dwedit commented Mar 10, 2022

It's about having the debugged EXE start up with a specific initial directory, and this option being remembered until the debugger is closed, or another EXE is opened in the debugger. Using the Restart command should keep it the startup directory the same.

I created this issue before discovering the "init" command, due to not finding this anywhere in the documentation. I had checked the online help for how to set the startup directory. Looking for words like 'initial directory', 'startup directory', 'working directory', etc led nowhere. It turns out the documentation for the "init" command uses the phrase "Current Folder", which is different than any term I was looking for,

Even with the "Init" command supporting setting a start directory, it's just as unfriendly as running it from the command prompt, especially if the setting doesn't persist after using the Restart button.

@mrexodia
Copy link
Member

@mrexodia mrexodia commented Mar 10, 2022

If it cannot be modified at runtime the current idea for the implementation can be changed. I’ll update the documentation to include those phrases in the meantime.

@Dwedit
Copy link
Author

@Dwedit Dwedit commented Mar 10, 2022

Applications can change the working directory, but they can't change the Command Line parameters. So changing the Current Working Directory and changing the Initial Directory really should be two different things. They shouldn't be unified under one text field.

Not like the situation with the Command Line parameters, which don't change, so specifying the "now" value and the "next time" value are the same thing for command line parameters.

@mrexodia
Copy link
Member

@mrexodia mrexodia commented Mar 10, 2022

🤷🏻‍♂️ I think it's fine. Once there is a function to change the working directory the details can be changed. For example if you set the working directory at the system breakpoint that could be the initial directory for the next startup.

@rajkumarananthu
Copy link
Contributor

@rajkumarananthu rajkumarananthu commented Apr 1, 2022

Hi @mrexodia , I tried searching for how SetCurrentDirectory() is implemented for reverse engineering, but couldn't find it, can you please help me here, may be I haven't put enough efforts here.

@mrexodia
Copy link
Member

@mrexodia mrexodia commented Apr 1, 2022

I’m afraid it might be a bit more complicated than I thought. I’ll try to take a look, but I forgot that the working directory is more intricate than the command line

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature good first issue gui
Projects
None yet
Development

No branches or pull requests

3 participants