Closed Shenmarukai closed 8 months ago
Hi Shane,
Can you please try to rerun without --no-semantics? This can cause problems sometimes.
It’s also very suspicious that OOAnalyzer did not find any new or delete functions. If you know how, finding those and passing them via --new-method and --delete-method would also probably help your analysis.
If theses do not help, I’ll ask you to provide some of your files so I can take a look in more detail.
Ed
From: Shane Mulcahy @.> Date: Friday, March 8, 2024 at 10:32 AM To: cmu-sei/pharos @.> Cc: Subscribed @.***> Subject: [cmu-sei/pharos] Unknown message: error(system_error(initialSanityChecks)) error from ooprolog (Issue #261) Warning: External Sender - do not click links or open attachments unless you recognize the sender and know the content is safe.
So essentially I'm trying to recover C++ class information from a 32 bit - PE-i386 format - executable compiled with MSVC. Im unsure of what version of MSVC was used to compile the executable, but I do have information on when it was compiled so the version of MSVC must be before this date -> Tue Dec 9 13:22:45 2003, so I think it must have been compiled with Visual C++ .NET 2003 / Visual C++ 7.1 or earlier:
F3.exe: file format pei-i386
executable 32 bit words
Time/Date Tue Dec 9 13:22:45 2003 Magic 010b (PE32) MajorLinkerVersion 7 MinorLinkerVersion 0 MajorOSystemVersion 4 MinorOSystemVersion 0 MajorImageVersion 0 MinorImageVersion 0 MajorSubsystemVersion 4 MinorSubsystemVersion 0 Win32Version 00000000 Subsystem 00000002 (Windows GUI)
I installed pharos via the docker image from:
I am running the docker image via:
The following is a summary of the outputs of each step. I can also provide the .exe file, .ser file, facts.pl file, results.pl file, and/or .log file if required.
Partitioning is successful:
OPTI[INFO ]: Analyzing executable: /data/F3.exe
OPTI[INFO ]: ROSE stock partitioning took 14.9721 seconds.
OPTI[INFO ]: Partitioned 731129 bytes, 244954 instructions, 56272 basic blocks, 65 data blocks and 3480 functions.
OPTI[INFO ]: Function partitioning took 677.933 seconds.
OPTI[INFO ]: Writing serialized data to "/data/F3.ser".
OPTI[INFO ]: Writing serialized data took 67.9488 seconds.
OPTI[INFO ]: Partitioned 2384469 bytes, 731889 instructions, 171589 basic blocks, 10343 data blocks and 17533 functions.
Analysis I think is successful:
OPTI[INFO ]: Analyzing executable: /data/F3.exe
OPTI[INFO ]: OOAnalyzer version 1.0.
OPTI[INFO ]: Reading serialized data from "/data/F3.ser".
OPTI[INFO ]: Reading serialized data took 34.7078 seconds.
OPTI[INFO ]: Partitioned 2384469 bytes, 731889 instructions, 171589 basic blocks, 10343 data blocks and 17533 functions.
...
OOAN[ERROR]: Found only 17285 functions of 17301 specifically requested for analysis.
OOAN[ERROR]: No new() methods were found. Heap objects may not be detected.
OOAN[ERROR]: No delete() methods were found. Object analysis may be impaired.
OPTI[WARN ]: OOAnalyzer did not perform C++ class analysis.
OPTI[INFO ]: OOAnalyzer analysis complete.
Awk prints showing that object oriented information was identified:
awk -F( '{print $1}' /data/F3-facts.pl | sort | uniq -c 1 % Object fact exporting complete. 1 % Prolog facts autogenerated by OOAnalyzer.
105089 callParameter
43197 callReturn
52605 callTarget
33022 callingConvention
1 fileInfo
36110 funcParameter
6725 funcReturn
7375 initialMemory
44654 methodMemberAccess
5825 noCallsAfter
5853 noCallsBefore
61 possibleVBTableWrite
1105 possibleVFTableWrite
7178 possibleVirtualFunctionCall
446 rTTIBaseClassDescriptor
403 rTTIClassHierarchyDescriptor
440 rTTICompleteObjectLocator
421 rTTITypeDescriptor
1133 returnsSelf
3028 thisPtrAllocation
24989 thisPtrDefinition
3402 thisPtrOffset
114 thunk
68 uninitializedReads
Ooprolog then unfortunately errors out with "Unknown message: error(system_error(initialSanityChecks))":
ooprolog --facts /data/F3-facts.pl --results /data/F3-results.pl --log-level=6 >/data/F3.log
[29] prolog_stack:get_prolog_backtrace(100,[frame(29,clause(
[28] throw_with_backtrace(error(system_error(initialSanityChecks))) at /usr/local/share/pharos/prolog/oorules/util.pl:185
[26] solve_internal at /usr/local/share/pharos/prolog/oorules/setup.pl:679
[25] catch(user:solve_internal,_25826564,user:((_25826632=error(resource_error(private_table_space),_25826646)->complain_table_space(ooscript);_25826696=error(resource_error(stack),_25826710)->complain_stack_size(ooscript);true),throw(_25826742))) at /usr/local/lib/swipl/boot/init.pl:562
[24] solve(ooscript) at /usr/local/share/pharos/prolog/oorules/setup.pl:617
[23] psolve_no_halt('
[22] catch(user:psolve_no_halt(stream(
[21] catch_with_backtrace('
[20] run_with_backtrace('
[19]
[18] with_output_to(
[17] setup_call_catcher_cleanup(user:(var('/data/F3-results.pl')->open_null_stream(
[15] setup_call_catcher_cleanup(user:open('/data/F3-facts.pl',read,
[12] run([script('/usr/local/bin/ooprolog'),json(_25827822),ground(_25827842),rtti(true),guess(true),config(_25827902),stacklimit(200000000000),tablespace(200000000000),oorulespath(_25827962),halt(true),load_only(false),help(_25828022),facts('/data/F3-facts.pl'),results('/data/F3-results.pl'),loglevel(6)]) at /usr/local/bin/ooprolog:235
[9] catch(user:main(['/usr/local/bin/ooprolog','--facts','/data/F3-facts.pl','--results','/data/F3-results.pl','--log-level=6']),_25828146,user:(print_message(error,_25828276),halt(1))) at /usr/local/lib/swipl/boot/init.pl:562
[7] catch(user:main,_25828350,'$toplevel':true) at /usr/local/lib/swipl/boot/init.pl:562
[6] catch_with_backtrace('
Note: some frames are missing due to last-call optimization.
Re-run your program in debug mode (:- debug.) to get more detail.
ERROR: /data/F3-facts.pl:383247:
ERROR: Unknown message: error(system_error(initialSanityChecks))
— Reply to this email directly, view it on GitHubhttps://github.com/cmu-sei/pharos/issues/261, or unsubscribehttps://github.com/notifications/unsubscribe-auth/AL6ZAVE6AEVSLLSEUOVCHHLYXHKXVAVCNFSM6AAAAABENACIDGVHI2DSMVQWIX3LMV43ASLTON2WKOZSGE3TMMRWGY2TEMY. You are receiving this because you are subscribed to this thread.Message ID: @.***>
Ok thank you, I will attempt without --no-semantics. And for adding the new and delete functions via --new-method and --delete-method, how would I go about doing that. Would I find them manually using a disassembler and then pass them in in some format?
Yes, you would try to identify them using a disassembler and then pass the addresses as arguments. If you can’t, do worry about it for now.
My colleague also noted that the “OOAN[ERROR]: Found only 17285 functions of 17301 specifically requested for analysis.” error is unusual. Could you upload a copy of that entire log if you have it?
From: Shane Mulcahy @.> Date: Friday, March 8, 2024 at 10:57 AM To: cmu-sei/pharos @.> Cc: Edward J Schwartz @.>, Comment @.> Subject: Re: [cmu-sei/pharos] Unknown message: error(system_error(initialSanityChecks)) error from ooprolog (Issue #261) Warning: External Sender - do not click links or open attachments unless you recognize the sender and know the content is safe.
Ok thank you, I will attempt without --no-semantics. And for adding the new and delete functions via --new-method and --delete-method, how would I go about doing that. Would I find them manually using a disassembler and then pass them in in some format?
— Reply to this email directly, view it on GitHubhttps://github.com/cmu-sei/pharos/issues/261#issuecomment-1985947722, or unsubscribehttps://github.com/notifications/unsubscribe-auth/AL6ZAVHX7J4CR2YLEUBX7BLYXHNYDAVCNFSM6AAAAABENACIDGVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMYTSOBVHE2DONZSGI. You are receiving this because you commented.Message ID: @.***>
Ok, I am testing it without --no-semantics right now. Here is the log for the previous attempt: F3-log.zip
Can you provide the log for the fact generation step?
From: Shane Mulcahy @.> Date: Friday, March 8, 2024 at 11:14 AM To: cmu-sei/pharos @.> Cc: Edward J Schwartz @.>, Comment @.> Subject: Re: [cmu-sei/pharos] Unknown message: error(system_error(initialSanityChecks)) error from ooprolog (Issue #261) Warning: External Sender - do not click links or open attachments unless you recognize the sender and know the content is safe.
Ok, I am testing it without --no-semantics right now. Here is the log for the previous attempt: F3-log.ziphttps://github.com/cmu-sei/pharos/files/14540426/F3-log.zip
— Reply to this email directly, view it on GitHubhttps://github.com/cmu-sei/pharos/issues/261#issuecomment-1985972750, or unsubscribehttps://github.com/notifications/unsubscribe-auth/AL6ZAVEZOSC3OTWODCWDK43YXHPMBAVCNFSM6AAAAABENACIDGVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMYTSOBVHE3TENZVGA. You are receiving this because you commented.Message ID: @.***>
Here is the facts.pl: F3-facts.zip
The attempt without --no-semantics failed as well. I've include a text file of the full console session, the .log file, and the facts.pl file. It did run out of memory when analyzing so I reduced the memory limit so it wouldn't run out of memory. I'm going to try it again on my other computer that has more ram. F3-logs.zip
Thanks, we were able to replicate the problem using your facts file. I will take a look in more detail and see what is going on.
Ok, thank you!
These are mostly notes to myself.
reasonMergeVFTables_A(constructor, 0x673a20, 0x5006f0, 0x673a20, 0, factVFTableWrite(0x500709, 0x5006f0, 0, 0x673a20)).
Concluding mergeVFTables(0x673a20, 0x5006f0).
Retracting factObjectInObject(0x673944, 0x5006f0, 0) and asserting factObjectInObject(0x673944, 0x673a20, 0) ...
Retracting factObjectInObject(0x673944, 0x5006f0, 0x6c) and asserting factObjectInObject(0x673944, 0x673a20, 0x6c) ...
Retracting factObjectInObject(0x673944, 0x5006f0, 0xa4) and asserting factObjectInObject(0x673944, 0x673a20, 0xa4) ...
Retracting factObjectInObject(0x673944, 0x5006f0, 0xdc) and asserting factObjectInObject(0x673944, 0x673a20, 0xdc) ...
Class 0x673944 inherits from 0x673a20 at offsets 0 and 0x6c
I'm confused because clearly the same problem was already happening with 0x673944 and 0x5006f0.
Edit: Ah, because of this fact: factDerivedClass(0x673944, 0x673a20, 0).
(look at insanityInheritanceTwice)
So that fact comes from here:
% Because RTTI tells us so for a non-virtual base class.
reasonDerivedClass_D(0x6fbba4, 0x6fbb88, 0x673944, 0x673a20, 0).
This is usually pretty reliable.
The other one originates here:
% This rule is a special case of the reasonObjectInObject_E, that relies on the fact that it
% does not matter whether the InnerClass and OuterClass are provably different or whether
% they're just currently not assigned to the same class. The key observation is that the
% distinction only matters when offset is non-zero, because that fact alone rules out the
% possibility that the two classes are in fact the same class.
reasonObjectInObject_D(0x4fb5b0, 0x5006f0, 0x6c, validMethodCallAtOffset(0x4fb62e, 0x4fb5b0, 0x5006f0, 0x6c)).
[eschwartz@pd4 f3]$ ~mwd/tmp/plogtrace.py --forward log 'factObjectInObject(0x673944, 0x673a20, 0x6c)'
47864: Concluding factObjectInObject(0x4fb5b0, 0x5006f0, 0x6c).
543219: Merging class 0x4fb5b0 into 0x673944 ...
543225: Retracting factObjectInObject(0x4fb5b0, 0x5006f0, 0x6c) and asserting factObjectInObject(0x673944, 0x5006f0, 0x6c) ...
555075: Merging class 0x5006f0 into 0x673a20 ...
555083: Retracting factObjectInObject(0x673944, 0x5006f0, 0x6c) and asserting factObjectInObject(0x673944, 0x673a20, 0x6c) ...
Edit: Of course the merges could be wrong too...
I have a feeling that this is caused by a thisptr offset. Can you please upload the executable? I may have a private branch of OOAnalyzer that may work on this.
Here is the executable: F3.zip
Thanks. OK, there are two problematic functions.
0x4fb5b0 installs DerivedClass::vftable, and calls 0x5006f0 a bunch. 0x5006f0 install Base::vftable to offset 0.
Now it looks like 0x4fb5b0 is a constructor for DerivedClass, and 0x5006f0 is a constructor for BaseClass, but that may not be true.
Let's look at the reasonObjectInObject_D conclusion. It is based on the call at 0x4fb62e, in 0x4fb5b0, which calls 0x5006f0. It basically says that because one constructor calls the other at offset 0, there must be an object relationship.
Here is the decompilation of 0x4fb5b0; I called 0x5006f0 "other_problem".
But the same constructor is called at multiple offsets, which suggests that they are all embedded objects instead of inheritance. So maybe one of the merge conclusions is wrong.
543219: Merging class 0x4fb5b0 into 0x673944 ...
This merges the MaybeDerivedConstructor with Derived::vftable.
reasonMergeVFTables_A(constructor, 0x673944, 0x4fb5b0, 0x673944, 0, factVFTableWrite(0x4fb5e0, 0x4fb5b0, 0, 0x673944)).
This rule basically says that because 0x4fb5e0 is a constructor, and we don't see any vftable overwrites, we can conclude that 0x4fb5e0 is part of the derived class.
We conclude that 0x4fb5e0 is a constructor because it installs a vftable before calling a constructor.
This all seems fine to me.
One possibility is that the derived class really does inherit from the base class. But then it embeds it too?
Or, maybe there is some templated class that shares a common constructor?
Whatever this binary is doing is kind of weird. But I think this is probably a reasonable workaround for now:
diff --git a/share/prolog/oorules/insanity.pl b/share/prolog/oorules/insanity.pl
index b99cef92..28e613a9 100644
--- a/share/prolog/oorules/insanity.pl
+++ b/share/prolog/oorules/insanity.pl
@@ -68,7 +68,8 @@ insanityInheritanceTwice(Out) :-
% making some stupid guesses in which we inherit the first instance of a class and then
% embed the rest. Maybe a better fix would be to modify guessDerivedClass so that we don't
% make the guess if there are multiple objectInObject facts.
- factObjectInObject(A,B,O2),
+ factDerivedClass(A,B,O2),
+ %factObjectInObject(A,B,O2),
iso_dif(O1, O2),
Out = (
Apply that patch and then rerun the ooprolog
step. I haven't run to completion yet, but it completes initial reasoning with this change at least.
Thank you! How would I apply that patch?
Probably the easiest way is to find the insanity.pl file in the docker container and manually edit it using vi, nano, or another text editor.
Alternatively if you find the directory of insanity.pl and enter it, you should be able to run patch -p4 and paste in the patch. (I could be wrong on the 4, try 3 or 5 if it doesn't work).
Ok, I will try that.
So far it seems to be working. Its been running for while and keeps logging more info, so hopefully it runs to completion!
Thank you so much! It worked this time. I have the json output now! I really appreciate the help, this program seems really amazing, and will be really useful for me!
Here are all of the outputs from the successful run, would have included the log file but its too large: F3.zip
Very glad to hear it!
I think probably what happened is that your program has a class like this:
struct D : public B {
B b2;
B b3;
};
I’ve seen this once before, but it’s very rare.
So essentially I'm trying to recover C++ class information from a 32 bit - PE-i386 format - executable compiled with MSVC. Im unsure of what version of MSVC was used to compile the executable, but I do have information on when it was compiled so the version of MSVC must be before this date -> Tue Dec 9 13:22:45 2003, so I think it must have been compiled with Visual C++ .NET 2003 / Visual C++ 7.1 or earlier:
I installed pharos via the docker image from:
docker pull seipharos/pharos
I am running the docker image via:
docker run --rm -it -v /dir:/dir seipharos/pharos
The following is a summary of the outputs of each step. I can also provide the .exe file, .ser file, facts.pl file, results.pl file, and/or .log file if required.
Partitioning is successful:
partition --serialize=/data/F3.ser --maximum-memory=24000 --no-semantics /data/F3.exe
Analysis I think is successful:
ooanalyzer --serialize=/data/F3.ser --maximum-memory 28000 --no-semantics --prolog-facts=/data/F3-facts.pl --threads=16 --per-function-timeout=1000 /data/F3.exe
Awk prints showing that object oriented information was identified:
awk -F\( '{print $1}' /data/F3-facts.pl | sort | uniq -c 1 % Object fact exporting complete. 1 % Prolog facts autogenerated by OOAnalyzer.
Ooprolog then unfortunately errors out with "Unknown message: error(system_error(initialSanityChecks))":
ooprolog --facts /data/F3-facts.pl --results /data/F3-results.pl --log-level=6 >/data/F3.log