But it sure is interesting to learn about all the tools that are out there thanks to various contests online including:
Disassembler which let's you know what's in a binary.
SWI Prolog. Many of these problems need a constraint solver. If you can believe it, people are still using Prolog to analyze constraints. Pomona has a good (9 year old!) tutorial on it. Note that this use the command line interface which is what you need.
The syntax is both short and strange. Basically all commands end in a period. That makes sense, it is a declarative:

# This loads the set of facts in hello.pl using their syntactic bracket sugar
[ 'hello.pl' ].
# Or less idiomatically and fitting into the use of single quotes for strings and an function()
consult('hello.pl').
# And to see all the rules, run a listing
listing.


In terms of actually learning the language, this is the learnprolognow.com is the top tutorial hit, but here are some notes:

• Inference you can have an and condition this way
# This means that rich is happy if he is coding or has eaten. Yes, this seems backwards, but it is how it works
happy(rich) := coding(rich), eaten(rich)
# This means rich is happy if he is either coding or eating
happy(rich) := coding(rich); eaten(rich)


As another weirdness any upper cases are variables. So What is a variable while what is a constant string. Also, it allows function overloading, so love(donkey) and love(morning, walk) are actually two different functions are are technically denoted as love/1(donkey) and love/2(morning,walk)
The most interesting idea is recursion by definition. It is much like mathematics as it is functional and not procedural and like all recursions, there is a 0 rule first and then a recursion. And because prolog picks up rules in order, it's important to have the null rule first, otherwise it will never terminate.

descend(X,Y)  :-  child(X,Y).
# The recursion
descend(X,Y)  :-  child(X,Z),
descend(Z,Y)


The list processing is also really tight, but basically a list is bracketed [a, b, c] and you can get the head and the tail of a list (car and cdr if you remember Lisp) like this so the variable Head would have a and the Tail would have [b, c, d]

[Head | Tail] = [a, b, c, d].


What is kind of cool is that you can extract various list elements by using the syntax with a common, so First is a, Second is b and Tail is [c,d]

[First, Second | Tail = [a, b, c, d].