Skip to content

Added functional tests, fixed private methods and variables scramblers #42

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

Open
wants to merge 36 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
f121e8c
wip
Mar 3, 2017
8e88122
test
Mar 6, 2017
947a71c
deleted mock
Mar 6, 2017
76298e3
reverted obfuscator
Mar 6, 2017
41be1dd
reverted services yml
Mar 6, 2017
7d8022e
tests
Mar 7, 2017
87be227
fix
Mar 7, 2017
be366c4
fix
Mar 7, 2017
6c9fdae
functional tests added
Mar 9, 2017
b2705db
Merge pull request #1 from Cheburon/functional-test
Cheburon Mar 9, 2017
754fe32
added more scramblers
Mar 9, 2017
72ea197
Merge pull request #2 from Cheburon/functional-test-more-scramblers
Cheburon Mar 9, 2017
8b81fe5
Update services.yml
Cheburon Mar 9, 2017
390514a
fix scramble private methods
Mar 10, 2017
d0e2e69
added private property scrambler fixes
Mar 10, 2017
49227d9
Merge pull request #3 from Cheburon/fix-private-method-scrambler
Cheburon Mar 10, 2017
d23a99a
added php7 support
Apr 4, 2017
0710c97
Merge pull request #4 from Cheburon/CLOUD-11918-php-7-support
Cheburon Apr 4, 2017
9ef2d0e
fix use scramble
Apr 4, 2017
94f054e
Merge pull request #5 from Cheburon/CLOUD-11919-obfuscation-use-bug
Cheburon Apr 4, 2017
9104497
static private property fixed
Apr 5, 2017
b0af549
Merge pull request #6 from Cheburon/CLOUD-11920-obfuscate-private-sta…
Cheburon Apr 5, 2017
9fe6b01
fix obfuscator error
Apr 5, 2017
81c8f31
Merge pull request #7 from Cheburon/CLOUD-11922-obfuscate-error
Cheburon Apr 5, 2017
d4e351f
fix use extends and implements
Apr 6, 2017
1777fdc
Merge pull request #8 from Cheburon/fix-obfuscator-use-extends
Cheburon Apr 6, 2017
6c8cc2f
fix
Apr 6, 2017
633518d
Merge pull request #9 from Cheburon/fix-typehint-use-bug
Cheburon Apr 6, 2017
09264e1
fix
Apr 6, 2017
301684a
fix
Apr 6, 2017
19d48f9
Merge pull request #10 from Cheburon/fix-return-typehint-use
Cheburon Apr 6, 2017
b4caa1a
fix
Apr 6, 2017
33d0ef5
fix
Apr 7, 2017
0cdc636
Merge pull request #11 from Cheburon/fix-php7-params
Cheburon Apr 7, 2017
a8bd3b5
fix
Apr 20, 2017
dd92f56
Merge pull request #12 from Cheburon/fix-use-typehint
Cheburon Apr 20, 2017
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
],

"require": {
"nikic/php-parser": "~1@dev",
"nikic/php-parser": "~3@dev",
"symfony/console": "~2.5",
"symfony/dependency-injection": "~2.5",
"symfony/config": "~2.5",
Expand Down
2 changes: 2 additions & 0 deletions phpunit.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
<phpunit bootstrap="tests/phpunit.php" colors="true">
</phpunit>
9 changes: 5 additions & 4 deletions src/Naneau/Obfuscator/Node/Visitor/ScramblePrivateMethod.php
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,9 @@ public function beforeTraverse(array $nodes)
->resetRenamed()
->skip($this->variableMethodCallsUsed($nodes));

$this->scanMethodDefinitions($nodes);
if (!$this->shouldSkip()) {
$this->scanMethodDefinitions($nodes);
}

return $nodes;
}
Expand All @@ -75,8 +77,7 @@ public function enterNode(Node $node)
}

// Scramble calls
if ($node instanceof MethodCall || $node instanceof StaticCall) {

if (($node instanceof MethodCall && $node->var->name === 'this') || ($node instanceof StaticCall && $node->class instanceof Node\Name && $node->class->toString() === 'self')) {
// Node wasn't renamed
if (!$this->isRenamed($node->name)) {
return;
Expand All @@ -96,7 +97,7 @@ public function enterNode(Node $node)
private function variableMethodCallsUsed(array $nodes)
{
foreach ($nodes as $node) {
if ($node instanceof MethodCall && $node->name instanceof Variable) {
if ($node instanceof MethodCall && $node->name instanceof Variable && $node->var->name === "this") {
// A method call uses a Variable as its name
return true;
}
Expand Down
13 changes: 12 additions & 1 deletion src/Naneau/Obfuscator/Node/Visitor/ScramblePrivateProperty.php
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,18 @@ public function enterNode(Node $node)
{
if ($node instanceof PropertyFetch) {

if (!is_string($node->name)) {
if (!is_string($node->name) || $node->var->name !== "this") {
return;
}

if ($this->isRenamed($node->name)) {
$node->name = $this->getNewName($node->name);
return $node;
}
}

if ($node instanceof Node\Expr\StaticPropertyFetch) {
if ((string)$node->class !== "self") {
return;
}

Expand Down
69 changes: 66 additions & 3 deletions src/Naneau/Obfuscator/Node/Visitor/ScrambleUse.php
Original file line number Diff line number Diff line change
Expand Up @@ -88,13 +88,16 @@ public function enterNode(Node $node)
$extends = $node->extends->toString();
if ($this->isRenamed($extends)) {
$node->extends = new Name($this->getNewName($extends));
} elseif ($this->isRenamed($node->extends->getFirst())) {
reset($node->extends->parts);
$node->extends->parts[key($node->extends->parts)] = $this->getNewName($node->extends->getFirst());
}
}

// Classes that implement an interface
if ($node->implements !== null && count($node->implements) > 0) {

$implements = array();
$implements = [];

foreach($node->implements as $implementsName) {

Expand All @@ -104,6 +107,10 @@ public function enterNode(Node $node)
if ($this->isRenamed($oldName)) {
// If renamed, set new one
$implements[] = new Name($this->getNewName($oldName));
} elseif ($this->isRenamed($implementsName->getFirst())) {
reset($implementsName->parts);
$implementsName->parts[key($implementsName->parts)] = $this->getNewName($implementsName->getFirst());
$implements[] = $implementsName;
} else {
// If not renamed, pass old one
$implements[] = $implementsName;
Expand All @@ -116,16 +123,67 @@ public function enterNode(Node $node)
return $node;
}

if ($node instanceof Node\Stmt\ClassMethod || $node instanceof Node\Expr\Closure) {

if ($node->returnType instanceof Name) {
// Name
$name = $node->returnType->toString();

// Has it been renamed?
if ($this->isRenamed($name)) {
$node->returnType = $this->getNewName($name);
return $node;
} elseif ($this->isRenamed($node->returnType->getFirst())) {
reset($node->returnType->parts);
$node->returnType->parts[key($node->returnType->parts)] = $this->getNewName($node->returnType->getFirst());
return $node;
}
}

if ($node->returnType instanceof Node\NullableType && $node->returnType->type instanceof Name) {
// Name
$name = $node->returnType->type->toString();

// Has it been renamed?
if ($this->isRenamed($name)) {
$node->returnType->type = $this->getNewName($name);
return $node;
} elseif ($this->isRenamed($node->returnType->type->getFirst())) {
reset($node->returnType->type->parts);
$node->returnType->type->parts[key($node->returnType->type->parts)] = $this->getNewName($node->returnType->type->getFirst());
return $node;
}
}
}

if ($node instanceof Param && $node->type instanceof Node\NullableType && $node->type->type instanceof Name) {
// Name
$name = $node->type->type->toString();

// Has it been renamed?
if ($this->isRenamed($name)) {
$node->type->type = $this->getNewName($name);
return $node;
} elseif ($this->isRenamed($node->type->type->getFirst())) {
reset($node->type->type->parts);
$node->type->type->parts[key($node->type->type->parts)] = $this->getNewName($node->type->type->getFirst());
return $node;
}
}

// Param rename
if ($node instanceof Param && $node->type instanceof Name) {

// Name
$name = $node->type->toString();

// Has it been renamed?
if ($this->isRenamed($name)) {
$node->type = $this->getNewName($name);
return $node;
} elseif ($this->isRenamed($node->type->getFirst())) {
reset($node->type->parts);
$node->type->parts[key($node->type->parts)] = $this->getNewName($node->type->getFirst());
return $node;
}
}

Expand All @@ -138,7 +196,6 @@ public function enterNode(Node $node)
|| $node instanceof NewExpression
|| $node instanceof InstanceOfExpression
) {

// We need to be in a class for this to work
if (empty($this->classNode)) {
return;
Expand All @@ -160,6 +217,12 @@ public function enterNode(Node $node)
if ($this->isRenamed($name)) {
$node->class = new Name($this->getNewName($name));
return $node;
} else {
if ($this->isRenamed($node->class->getFirst())) {
reset($node->class->parts);
$node->class->parts[key($node->class->parts)] = $this->getNewName($node->class->getFirst());
return $node;
}
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/Naneau/Obfuscator/Resources/services.yml
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ services:

# Parser
obfuscator.parser:
class: PhpParser\Parser
class: PhpParser\Parser\Php7
arguments:
- @obfuscator.lexer

Expand Down
7 changes: 7 additions & 0 deletions tests/Base.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?php

namespace Tests;

class Base extends \PHPUnit_Framework_TestCase {

}
32 changes: 32 additions & 0 deletions tests/ObfuscateTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php

namespace Tests;

class ObfuscateTest extends Base {

const AFTER_PATH = "/after";
const BEFORE_PATH = "/before";
const EXPECTED_PATH = "/expected";

protected function tearDown() {
$files = glob(__DIR__ . self::AFTER_PATH . "/*");
foreach ($files as $file) {
unlink($file);
}
rmdir(__DIR__ . self::AFTER_PATH);
}

public function testObfuscate() {
shell_exec("./bin/obfuscate obfuscate " . __DIR__ . self::BEFORE_PATH . " " . __DIR__ . self::AFTER_PATH . " --config=" . __DIR__ . "/config.yml");
$expectedFileNames = scandir(__DIR__ . self::EXPECTED_PATH);
foreach ($expectedFileNames as $expectedFileName) {
if ($expectedFileName === '.' || $expectedFileName === '..') {
continue;
}
if (!file_exists(__DIR__ . self::AFTER_PATH . "/" . $expectedFileName)) {
$this->fail("{$expectedFileName} not found");
}
$this->assertEquals(file_get_contents(__DIR__ . self::EXPECTED_PATH . "/" . $expectedFileName), file_get_contents(__DIR__ . self::AFTER_PATH . "/" . $expectedFileName));
}
}
}
21 changes: 21 additions & 0 deletions tests/before/Functions.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?php


function functionA($argumentVar) {
$localVarA = 3;
return $argumentVar + $localVarA;
}

function functionB() {
$localVarB = 5;
return functionB($localVarB);
}

function functionC(?int $a): ?string {
return $a === null ? null : "Output: " . $a;
}

$localVarMainA = "local value";
$localVarMainB = functionB();
$localVarMainA = functionA($localVarMainA);
functionC();
60 changes: 60 additions & 0 deletions tests/before/MultipleClasses.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
<?php

class FirstClass {

protected $_protectedProperty;
public $publicProperty;

protected function _protectedMethod() {
echo "This is protected method of first class";
}

public function publicMethod() {
echo "This is public method of first class";
}
}

class SecondClass extends FirstClass {

private $_privateProperty;

protected function _protectedMethod() {
parent::_protectedMethod();
echo "This is protected method of second class";
$this->_privateProperty = parent::$_protectedProperty;
}

public function publicMethod() {
parent::publicMethod();
echo "This is public method of second class";
$this->_privateProperty = parent::$publicProperty;
}

static public function anotherPublicMethod() {
}
}

class ThirdClass {

private $publicProperty;

static private function anotherPublicMethod() {

}

public function __construct(SecondClass $secondObject) {
$secondObject->publicMethod();
$secondObject::anotherPublicMethod();
$secondObject->publicProperty = 'test';
}

private function publicMethod() {
echo 'test';
}

protected function someFunc() {
$this->publicProperty = 'test';
$this->publicMethod();
self::anotherPublicMethod();
}
}
43 changes: 43 additions & 0 deletions tests/before/Namespaces.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<?php

namespace namespaceA;

class classA {

}

namespace namespaceC\namespaceD;

class classD {

}

interface interfaceA {

}

namespace namespaceB;

use namespaceA\classA as classC;
use namespaceC\namespaceD as namespaceDAlias;

class classB {

private $_objectA;

private $_objectB;

public function __construct() {
$this->_objectA = new classC();
$this->_objectB = new namespaceDAlias\classD();
}
}

class classE extends namespaceDAlias\classD implements namespaceDAlias\interfaceA {

public function method(?namespaceDAlias\classD $objectD) : ?namespaceDAlias\classD {
$func = function () : ?namespaceDAlias\classD {

};
}
}
Loading