-
Notifications
You must be signed in to change notification settings - Fork 666
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
Support Python 3.8 decompilation #449
Comments
@zrax do you have an idea how to support the new while loops? so we would need to maybe switch the if block inferred before to a while?
has this bytecode in 3.7:
whereas in 3.8, it's exactly the same only there is no SETUP_LOOP and POP_BLOCK, so the only thing here that differentiate it from a regular if statement, is the JUMP_ABSOLUTE or any other opcode that goes backwards like this. what way do you think we can solve this maybe? |
As a reference:
|
@TiZCrocodile I just noticed your message about loops in Python 3.8 now, after scratching my head on it for hours today :D Is it always true, that a If condition
While loop
EDIT1: something like this maybe: diff --git a/ASTNode.h b/ASTNode.h
index 22b90e1..d8423af 100644
--- a/ASTNode.h
+++ b/ASTNode.h
@@ -555,8 +555,10 @@ public:
void setEnd(int end) { m_end = end; }
-private:
+protected:
BlkType m_blktype;
+
+private:
int m_end;
list_t m_nodes;
@@ -575,6 +577,7 @@ public:
bool negative = false)
: ASTBlock(blktype, end), m_cond(std::move(cond)), m_negative(negative) { }
+ void inferToWhileLoop() { m_blktype = ASTBlock::BLK_WHILE; }
PycRef<ASTNode> cond() const { return m_cond; }
bool negative() const { return m_negative; }
diff --git a/ASTree.cpp b/ASTree.cpp
index fceef40..26b6593 100644
--- a/ASTree.cpp
+++ b/ASTree.cpp
@@ -1226,6 +1246,16 @@ PycRef<ASTNode> BuildFromCode(PycRef<PycCode> code, PycModule* mod)
curblock->append(tmp.cast<ASTNode>());
}
}
+ } else if (curblock->blktype() == ASTBlock::BLK_IF) {
+ /* in Python 3.8, SETUP_LOOP was removed for
+ while loop too. We infer IF conditions to
+ WHILE blocks when we meet a JUMP_ABSOLUTE */
+ if (mod->verCompare(3, 8) >= 0)
+ {
+ curblock.cast<ASTCondBlock>()->inferToWhileLoop();
+ stack = stack_hist.top();
+ stack_hist.pop();
+
+ PycRef<ASTBlock> tmp = curblock;
+ blocks.pop();
+ curblock = blocks.top();
+ curblock->append(tmp.cast<ASTNode>());
+ }
} else if (curblock->blktype() == ASTBlock::BLK_ELSE) {
stack = stack_hist.top();
stack_hist.pop(); EDIT2: There is a problem with the |
@Levak |
Well, I took it as a dare because of what I'm trying to decompile was Python 3.9 and I was like "is there really no one else on the planet able to decompile Python 3.8+?"
We need so much more tests - I just noticed that most of the compiled examples are for Python 2.x and were never recompiled for Python 3.x - So much features were added over time but not added to the test base? |
thats exactly why i started it too xD, i wanted to prove my friend that pyc on python 3.11 is not obfuscated and i can get the code, but im now checking here and there.
yea i agree with you, there is also wrong decompilation of some IFs conditions, we need to do more tests. |
So far, I have identified these cases for
When I try to add while-loop inference from My best example so far is this one:
Bytecode (Python 3.8) - condensed just to illustrate the relevant blocks
Here we can see that, respectively, from left to right, the last 2 and last I'm really starting to consider giving up Y_Y EDIT: Discussions regarding while/continue linked with #467 |
I realize now why it is so hard to infer while loops in Python 3.8 and 3.9. The jumps are optimized by the Python compiler. Here is an example:
As you can see, every single keyword can be found back. This is only true up to Python 3.9 included. In Python 3.10 they refined this control flow which makes this observation null. So the first step at inferring loops from ifs, is to probably resolve the dead links. |
pycdc.exe ursServer.pyc |
Tasks
BEGIN_FINALLY
END_ASYNC_FOR
CALL_FINALLY
POP_FINALLY
The text was updated successfully, but these errors were encountered: