Getting detailed version information of the executed program - windbg

I'm trying to get the version information of the executable from a crash dump. It's not that simple, so please read the whole question before you come up with an answer that does not work.
lm vm appname
Basically I can do lmv to get the version details, and that is exactly the information I want.
If you don't know how to get the version information of the executable, you can google a bit and get this answer, which suggests
lm vm appname (without .exe)
This works probably in 90% of the cases. However, it has the following two issues which I want to resolve in an automated analysis:
What is appname if I don't know the executable in advance?
In special cases like Notepad++, the module name is not notepad++ but rather notepad__
Now I can find out the executable name using |, but extracting the name of the executable from that output is not trivial.
Finding the exe in the list of modules
It is possible to find executables in the list of modules with a command like
.shell -ci "lmf" findstr "\.exe"
We can then extract the address and list the details with
.foreach /ps 9999 (exe {.shell -ci "lmf" findstr "\.exe"}) {lmva exe}
Still, there is a problem: .NET processes can load assemblies that are not DLLs but EXEs. In that case, the output might be wrong if the first result is not the main executable but a EXE loaded later.
List of modules
It is possible to get a list of modules using lm1m. And usually, the first one in that list is the executable.
It is then possible to extract the first line and get the details for it. A command looks like
.foreach /ps 9999 (exe {lm1m}) { lm vm ${exe}}
Unfortunately, it is not guaranteed that the executable is the first module. The modules are sorted by address. And IMHO it might happen that the executable is loaded at a higher address.
Question
How do I get lmv information for the main executable reliably.
Assumptions that can be made:
user mode crash dump of type /ma
only one process is being debugged

As mentioned in the comments by Jeroen Mostert, a suitable command might be
lmv a $exentry
This works, because lm is smart enough to accept address which are within a module. $exentry gives the entry point of the first executable.
You find the description in the pseudo register syntax:
$exentry: The address of the entry point of the first executable of the current process.
[Source: WinDbg help]
For the C# part, we can use the following piece of code for testing:
using System;
using System.IO;
using System.Reflection;
namespace exentry
{
class Program
{
static void Main()
{
var fullExe = Assembly.GetEntryAssembly().Location;
var path = Path.GetDirectoryName(fullExe);
var newexe = Path.Combine(path, "exentry2.exe");
File.Copy(fullExe, newexe);
Assembly.LoadFrom(newexe);
Console.WriteLine("Debug now");
Console.ReadLine();
}
}
}

Related

MAUI Storage Preferences exception [duplicate]

I am working on a program that I want to run a console command and save the output to a string. This program is installed by the user before running my program.
However, I have found I keep getting the error Cannot run program "XXXX" (in directory "C:\Users\accou\Downloads"): CreateProcess error=2, The system cannot find the file specified
For example, I have the program "Maui" that I have added to my system path:
Running in my Command Prompt:
C:\Users\accou\Downloads>maui
HELLO
C:\Users\accou\Downloads>
If I run the following code in Java I get the exception above
ProcessBuilder pb =
new ProcessBuilder("maui");
pb.directory(new File("C:\\Users\\accou\\Downloads"));
File log = new File("C:\\Users\\accou\\Downloads\\log.txt");
pb.redirectErrorStream(true);
pb.redirectOutput(ProcessBuilder.Redirect.appendTo(log));
Process p = pb.start();
assert pb.redirectInput() == ProcessBuilder.Redirect.PIPE;
assert pb.redirectOutput().file() == log;
assert p.getInputStream().read() == -1;
Exception:
Exception in thread "main" java.io.IOException: Cannot run program "maui" (in directory "C:\Users\accou\Downloads"): CreateProcess error=2, The system cannot find the file specified
at java.base/java.lang.ProcessBuilder.start(ProcessBuilder.java:1142)
at java.base/java.lang.ProcessBuilder.start(ProcessBuilder.java:1073)
at Application.main(Application.java:13)
Caused by: java.io.IOException: CreateProcess error=2, The system cannot find the file specified
at java.base/java.lang.ProcessImpl.create(Native Method)
at java.base/java.lang.ProcessImpl.<init>(ProcessImpl.java:483)
at java.base/java.lang.ProcessImpl.start(ProcessImpl.java:158)
at java.base/java.lang.ProcessBuilder.start(ProcessBuilder.java:1109)
... 2 more
I will get the same error if I try commands such as "dir" which I know 100% is available in windows.
However, if I can the command to the following it workes perfectly fine.
new ProcessBuilder("cmd.exe", "/c", "maui");
The following also works
new ProcessBuilder("maui.cmd");
Why is it that I cannot run "dir" or more importantly "maui" directly?
You're confusing ProcessBuilder with a shell. ProcessBuilder is not 'ask the dos box cmd shell to act as if we ran this statement', and when you type something in that black box, such as 'dir', that is not the same as 'ask the OS to execute this process'.
The shell does all sorts of intriguing transformations and interpretations of what you typed. That's cmd.exe (or, on other OSes, e.g. /usr/bin/bash), it is not the OS doing that, and java does not ship with a bash or cmd.exe baked in. It just asks the OS to do what you asked.
Thus, you can't use all these shellisms. Unfortunately, java tries to do some very basic shellisms, which just adds confusion. In particular:
The single-string argument variant will split on spaces to attempt to extract the executable to run + the arguments to pass.
On windows, *.txt and friends probably works. On other OSes it probably does not, as expanding a star into all matching files is a bashism. Best not use it.
built-ins, such as cd, pwd, test, dir, and others definitely do not work.
Relying on $PATH probably doesn't work, but this is one that java does sometimes try to apply. Still, best not rely on it.
Any fancy redirects and the like are all shellisms and do not work. You can't ask java to redirect to printer using foo.exe >PRN or /usr/bin/whatnot >/dev/printer. You can't write an if or a loop, or use %foo% or $foo or any other such things.
This leads to the following conclusion:
Do not ever use relative paths for anything ProcessBuilder related.
Do not ever try to squeeze the executable and the arguments into a single string; always use the multiple strings variant.
Don't rely on ANYTHING other than an absolute path, and absolute arguments.
If you need any shellisms of any sort, run cmd.exe /c C:\absolute\path\to\something.bat, or on posixy systems, /bin/bash -c /abs/path/to/shellscript, and strongly consider on windows to use System.getenv to get the installed location of windows, so you can absolute-path cmd to thatPath + "cmd.exe", so that you end up with "C:\\Windows\\cmd.exe" or equivalent (windows may not actually be installed there, hence, use env).
Unwieldy? Yeah. Don't use ProcessBuilder unless you know what you are doing.
In this case, if type maui on the command line, it's cmd.exe that figures out: Oh, hey, there is a maui.cmd in this dir on the path, surely they meant that. That's a shellism. Not baked into the OS itself, and java does not ship with cmd.exe built in, so that does not work. dir is not an executable but a built-in feature of cmd.exe. Same rule.
Java can do all these baked in things. There is no need to call dir - java can walk paths and give you all relevant info with e.g. the java.nio.file.Files API.

Autoconf : How to get program output in a string and check if another string is present in that

I am developing a Qt application in Python. It uses a resource file, which needs to be compiled. I am using autotools to manage compilation and installation of my projects.
Now, in order for the resource file to be usable by the application, it needs to be compiled with a certain version of the compilation program (pyrcc). I can get the version by putting the output of pyrcc -version in a variable in configure.ac. But then, I don't know how to check whether the string pyrcc5 is present in the output. If it is not present, I want to tell the user that his PyRCC programm has the wrong version, and abort configure.
Additionally, I would like to avoid the need of an extra variable for the program output, but instead do it like this (Pseudo code):
if "pyrcc5" not in output of "pyrcc -version":
say "pyrcc has wrong version"
exit 1
How can I do this ?
When writing a configure.ac for Autoconf, always remember that you are basically writing a shell script. Autoconf provides a host of macros that afford you a lot of leverage, but you can usually at least get an idea about basic "How can I do X in Autoconf?" questions by asking instead "How would I do X in a portable shell script?"
In particular, for ...
I would like to avoid the need of an extra variable for the program
output, but instead do it like this (Pseudo code):
if "pyrcc5" not in output of "pyrcc -version":
say "pyrcc has wrong version"
exit 1
... the usual tool for a portable shell script to use for such a task is grep, and, happily, the easiest way to apply it to the task does not require an intermediate variable. For example, this implements exactly your pseudocode (without emitting any extraneous messaging to the console):
if ! pyrcc -version | grep pyrcc5 >/dev/null 2>/dev/null; then
echo "pyrcc has wrong version"
exit 1
fi
That pipes the output of pyrcc -version into grep, and relies on the fact that grep exits with a success status if and only if it finds any matches.
You could, in fact, put exactly that in your configure.ac, but it would be more idiomatic to
Use the usual Autoconf mechanisms to locate pyrcc and grep, and to use the versions discovered that way;
Use the Autoconf AS_IF macro to write the if construct, instead of writing it literally;
Use standard Autoconf mechanisms for emitting a "checking..." message and reporting on its result; and
Use the standard Autoconf mechanism for outputting a failure message and terminating.
Of course, all of that makes the above considerably more complex, but also more flexible and portable. It might look like this:
AC_ARG_VAR([PYRCC], [The name or full path of pyrcc. Version 5 is required.])
# ...
AC_PROG_GREP
AC_CHECK_PROGS([PYRCC], [pyrcc5 pyrcc], [])
AS_IF([test "x${PYRCC}" = x],
[AC_MSG_ERROR([Required program pyrcc was not found])])
# ...
AC_MSG_CHECKING([whether ${PYRCC} has an appropriate version])
AS_IF([! pyrcc -version | grep pyrcc5 >/dev/null 2>/dev/null], [
AC_MSG_RESULT([no])
AC_MSG_ERROR([pyrcc version 5 is required, but ${PYRCC} is a different version])
], [
AC_MSG_RESULT([yes])
])
In addition to portability and conventional Autoconf progress messaging, that also gets the builder a way to specify a particular pyrcc executable to configure (by setting variable PYRCC in its environment), documents that in configure's help text, and exports PYRCC as a make variable.
Oh, and I snuck in a check for pyrcc under the name pyrcc5, too, though I don't know whether that's useful in practice.
The final result no longer looks much like the shell script fragment I offered first, I grant. But again, the pure shell script fragment could be used as is, and also, the fully Autoconfiscated version is derived directly from the pure script.

get user machines current working directory from perl cgi

i am trying to get the current working directory path using Perl
when i execute from ubuntu: $root#ubuntu:/var/test/geek# firefox http:/localhost/test.html, i get /var/cgi-bin as output in perl cgi page instead of /var/test/geek.
used perl code:
my $pwd=cwd();
bla bla
print "<h1> pwd </h1>";
above code gives path of test.pl not users working directory path
Edit: When i run the script alone from the terminal it works fine. for example:
$root#ubuntu:/var/test/geek# /var/cgi-bin/test.pl
i get /var/test/geek. but when i call the script in html page using submit button it gives path of perl script.
Each process has its own working directory that it inherits from its parent when it gets created.
cwd() returns the current process's working directory.
For a CGI script, the browser doesn't pass its working directory to the server as part of the request. To obtain that, you need to have code running on the client system that submits it. That might be an application that the user download, or possibly, but unlikely, some in-browser code, like Javascript / a Java applet (This info is likely hidden from in-browser code for security reasons though).
(The rest assumes Linux, it will likely differ on other operating systems)
The part below assumes that you are looking for the working directory of a user on the server:
In order to get a specific shell for a specific user's working directory, you would need to identify the PID for the shell and get the working directory from the /proc/<pid>/cwd symlink (To read these, the process must belong to the user running the code, or the code must run as root (Which is a bad idea for a CGI script)...). To get the PID of the shell, you likely need to start from the w command output, or its data source, /var/run/utmp. Sys::Utmp might be useful for this... You might then also need to retreive a whole lot of extra info to find all the processes that might have the working directory that you are looking for.
I think you are mixing the web server and the local user. The web server has a working directory when you run the script, and that is the one that cwd() returns.

Unrar script, error, in need of rar command for debian

I'm currently trying to get this script to work:
https://github.com/mj41/auto-unrar/blob/master/bin/unrar2.pl
The only problem is that I get the following error:
Entering directory 'Series'
Entering directory 'Series/SerieName'
Entering directory 'Series/SerieName/Season2'
Entering directory 'Series/SerieName/Season2/SerieNameS02E21.720p.HDTV.X264-DIMENSION'
Entering directory 'Series/SerieName/Season2/SerieNameS02E21.720p.HDTV.X264-DIMENSION/Sample'
Can't call method "List" on an undefined value at unrar2.pl line 973.
This line is rar_obj->List();
$rar_conf{'-verbose'} = $rar_ver if $rar_ver;
my $rar_obj = Archive::Rar->new( %rar_conf );
$rar_obj->List();
my #files_extracted = $rar_obj->GetBareList();
This is an old script, 3-4 years old and I changed a little like SHA1 to SHA and use Filesys::DfPortable; to Df
Does anyone know how I can fix this error :)?
EDIT:
I contacted the developer and he told me I needed to install a program that can handle rar commands. So how would I do that. I can't seem to be able to install unrar.
EDIT2:
What my problem is now, 2 of the 3 unrar packages aren't in my architecture, armhf.
To install the script yourself::::::::::::
https://github.com/jorricks/UNRAR
You need to pass the -archive parameter into the call to new() otherwise how will $rar_obj know which file it is supposed to be looking at?
I can't seem to be able to install unrar
That's not a particular good explanation of your problem. What did you try? What unexpected behaviour did you see?
From the tags on your question, it looks like you're running Debian. What do you see if you run sudo apt-get install unrar?
Update: My first comment was based on the code extract that you showed us. Looking at the full program code, I can see that %rar_conf has other values set in it (including the -archive option) before the section of code you gave us.
Looking at the source of the Archive::Rar module, it seems to assume that the program to use for dealing with the archives is called rar. So 7-Zip is not going to work.

Perl - Cannot get command line arguments in without explicitly putting "perl" before script call [duplicate]

This question already has answers here:
#ARGV is empty using ActivePerl in Windows 7
(4 answers)
Closed 9 months ago.
I'm running ActivePerl 5.8.8 build 822 on Win7 x64. We're working on a project that is about 60% C++, 15% perl, etc. The Perl is heavily used to link bits and pieces and various small utility applications together to create and pack our final data. So, for example, our VS2005 solution has post build events to create hard links to DLL's using a post build perl script which lives at some location on our development drive (it is part of PATH env var).
I found out quickly, that without explicitly putting "perl" to call the interpreter in-front of the postbuild.pl script call, it wouldn't accept command line arguments. I tested this further simply by going to the cmd window and doing the same with a "hello world" style perl script. No command line arguments were passed in when I say "bleh.pl arg1 arg2". But when I say "perl bleh.pl arg1 arg2" I get command line arguments.
When this failure occurs, perl reads zero command line arguments, and the #ARGV variable empty or null (whatever this crazy language does). So they're simply not passed in.
This is an issue because there are hundreds if not thousands of calls to perl scripts which I fear are not behaving correctly, and it is unreasonable to think I should have to prefix every .pl script invocation with perl explicitly, not to mention we're using version control and I don't want to commit all these garbage changes nor manage them in my stash.
PERL env var exists and points at the folder where the perl binary lives. As well as PATHEXT has .PL in it for perl scripts. Likewise, my PATH contains the folder entries to get to the scripts and to perl also.
Any help on how to figure this out would be immensely appreciated! Also, when I installed ActivePerl (I've done so many times now trying to figure this out). I allowed it to change my Path and associate file extensions in windows, which you would think would be the solution.
Thank you!
Your association is broken (incomplete). First, open a console and execute
assoc .pl
You'll get something like
.pl=SOMETHING
Then, execute
ftype SOMETHING
You should get something like
SOMETHING="C:\SOMEWHERE\bin\perl.exe" "%1" %*
but you'll get something like the following instead:
SOMETHING="C:\SOMEWHERE\bin\perl.exe" "%1"
To fix it, execute
ftype SOMETHING="C:\SOMEWHERE\bin\perl.exe" "%1" %*