pycdc icon indicating copy to clipboard operation
pycdc copied to clipboard

i make a anti pycdc so ez with a loop

Open hngocuyen opened this issue 6 months ago • 5 comments

antipycdc = ""

for i in range(10000):
    antipycdc += "1/int(0),"

antipycdc = "try:ngocuyencoder=(" + antipycdc + ")\nexcept:pass"

ANTI_PYCDC = f"""
try:pass
except:pass
else:pass
finally:pass
{antipycdc}
finally:int(2008-2006)
"""
print(ANTI_PYCDC)
#compile it to pyc and see a segment fault (>3.11 version)

when i custom a astree.cpp to bypass this , this break a code structure and it make a file to > 100mb

hngocuyen avatar Jun 01 '25 10:06 hngocuyen

lol

LinuxV3 avatar Jun 01 '25 11:06 LinuxV3

I tried to reproduce the issue myself, it's OK on python 3.10, then I tried 3.12 but -

@hngocuyen did you implement yourself the missed JUMP_BACKWARD opcode? it's not present in the main baseline...

 ./pycdc __pycache__/py_loop.cpython-312.pyc 
# Source Generated with Decompyle++
# File: py_loop.cpython-312.pyc (Python 3.12)

Unsupported opcode: JUMP_BACKWARD (226)
antipycdc = ''
# WARNING: Decompyle incomplete

greenozon avatar Jun 08 '25 13:06 greenozon

@greenozon not compile a

antipycdc = ""

for i in range(10000):
    antipycdc += "1/int(0),"

antipycdc = "try:ngocuyencoder=(" + antipycdc + ")\nexcept:pass"

ANTI_PYCDC = f"""
try:pass
except:pass
else:pass
finally:pass
{antipycdc}
finally:int(2008-2006)
"""
print(ANTI_PYCDC)
#compile it to pyc and see a segment fault (>3.11 version)

only compile all in ANTI_PYCDC mean

try:pass
except:pass
else:pass
finally:pass
try:ngocuyencoder=((1/int(0),1/int(0),1..............vv)
finally:int(2008-2006)

and compile to pyc

or u can compile it if python >= 3.11

try:pass
except:pass
else:pass
finally:pass

Image

Segmentation fault

i think you guys already know this bug, maybe it's just an open source project and it's free so u dont fix it, but thanks for this project , love.

hngocuyen avatar Jun 10 '25 17:06 hngocuyen

and for the jump_backward i add like this in astree.cpp

case Pyc::JUMP_BACKWARD_A:
{
    int delta = operand;
    if (mod->verCompare(3, 10) >= 0) {
        delta *= sizeof(uint16_t);
    }
    int offs = pos - delta;

    if (curblock->blktype() == ASTBlock::BLK_FOR) {
        bool is_jump_to_start = offs == curblock.cast<ASTIterBlock>()->start();
        bool should_pop_for_block = curblock.cast<ASTIterBlock>()->isComprehension();
        bool should_add_for_block = mod->majorVer() == 3 && mod->minorVer() >= 8 && is_jump_to_start && !curblock.cast<ASTIterBlock>()->isComprehension();

        if (should_pop_for_block || should_add_for_block) {
            PycRef<ASTNode> top = stack.top();

            if (top.type() == ASTNode::NODE_COMPREHENSION) {
                PycRef<ASTComprehension> comp = top.cast<ASTComprehension>();
                comp->addGenerator(curblock.cast<ASTIterBlock>());
            }

            PycRef<ASTBlock> tmp = curblock;
            blocks.pop();
            curblock = blocks.top();
            if (should_add_for_block) {
                curblock->append(tmp.cast<ASTNode>());
            }
        }
    } else if (curblock->blktype() == ASTBlock::BLK_ELSE) {
        stack = stack_hist.top();
        stack_hist.pop();

        blocks.pop();
        blocks.top()->append(curblock.cast<ASTNode>());
        curblock = blocks.top();

        if (curblock->blktype() == ASTBlock::BLK_CONTAINER
                && !curblock.cast<ASTContainerBlock>()->hasFinally()) {
            blocks.pop();
            blocks.top()->append(curblock.cast<ASTNode>());
            curblock = blocks.top();
        }
    } else {
        curblock->append(new ASTKeyword(ASTKeyword::KW_CONTINUE));
    }

    break;
}

in astnode.h

    enum ConversionFlag {
        NONE = 0,
        STR = 1,
        REPR = 2,
        ASCII = 3,
        CONVERSION_MASK = 0x03,
        HAVE_FMT_SPEC = 4,
        FMTSPEC = 4, # idk but when i add it , opcode is work
    };

hngocuyen avatar Jun 10 '25 17:06 hngocuyen

@greenozon not compile a

antipycdc = ""

for i in range(10000): antipycdc += "1/int(0),"

antipycdc = "try:ngocuyencoder=(" + antipycdc + ")\nexcept:pass"

ANTI_PYCDC = f""" try:pass except:pass else:pass finally:pass {antipycdc} finally:int(2008-2006) """ print(ANTI_PYCDC) #compile it to pyc and see a segment fault (>3.11 version)

only compile all in ANTI_PYCDC mean

try:pass except:pass else:pass finally:pass try:ngocuyencoder=((1/int(0),1/int(0),1..............vv) finally:int(2008-2006)

and compile to pyc

or u can compile it if python >= 3.11

try:pass except:pass else:pass finally:pass

Image

Segmentation fault

i think you guys already know this bug, maybe it's just an open source project and it's free so u dont fix it, but thanks for this project , love.

or maybe people just fix what they need when they do reverse engineering and that's not a common thing for programmers to do. for example, there are a lot of missing OPCodes for Python3.13 that I'm fixing and will soon make a PR, its not all of them because I don't need all of them.

This tool seems to be an advanced user tool for those who do reverse engineering, any sort of counter-measure you implement is going to be trivially reversed with the way python works. I would focus your anti-reversing protection on just making the labels unreadable, as they do on APKs when they're published to Google store. Trying to implement any sort of instruction rewriting to make reverse-engineer tools crash is sort of pointless, what you need to do is just make the effort of reversing cost more, getting rid of most strings is enough for that. I know you're an young guy, but professionally you should pay more attention to other things than trying to prevent people from reversing your software, if they want to do, there's nothing you can do to prevent sort of never distributing the executable and running it as a SaaS. As a fun experiment, that's totally fine.

Luiz-Monad avatar Jun 18 '25 16:06 Luiz-Monad