Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
53 changes: 53 additions & 0 deletions .github/workflows/pr-validation.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
name: PR Validation
on:
pull_request:
branches:
- main
paths:
- 'encrypted-execution/**'
- '8.5/**'
- '.github/workflows/**'
- 'test.sh'
- 'examples/**'

jobs:
validate:
runs-on: ubuntu-latest
timeout-minutes: 30
permissions:
contents: read
packages: write
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Build Encrypted PHP Image
run: |
echo "Building encrypted PHP image for PR validation..."
docker build -t ghcr.io/encrypted-execution/encrypted-php8.5-apache-debian:pr-test -f Dockerfile ../../..
shell: bash
working-directory: ./8.5/bookworm/apache/

- name: Run Test Suite
timeout-minutes: 20
run: |
echo "Running test suite..."
./test.sh pr-test
shell: bash
working-directory: .

- name: Test Symbol Scrambling
if: success()
run: |
if [ -f "Dockerfile.test-symbols" ]; then
echo "Testing symbol scrambling..."
docker build -t test-symbols:pr -f Dockerfile.test-symbols .
docker run --rm test-symbols:pr
else
echo "Symbol scrambling test not found, skipping"
fi
shell: bash
working-directory: .
69 changes: 69 additions & 0 deletions Dockerfile.test-symbols
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
# Test Dockerfile for symbol scrambling
# Minimal build to test scrambler changes

FROM golang:1.21-bookworm AS builder

WORKDIR /build

# Copy scrambler source
COPY encrypted-execution/tools/scrambler/*.go encrypted-execution/tools/scrambler/go.mod ./

# Build scrambler
RUN go build -o php-scrambler .

# Runtime stage
FROM debian:bookworm-slim

# Install Python for transformation script
RUN apt-get update && apt-get install -y python3 && rm -rf /var/lib/apt/lists/*

# Copy built scrambler
COPY --from=builder /build/php-scrambler /usr/local/bin/

# Copy transformation script
COPY encrypted-execution/tools/scrambler/transform-php.py /usr/local/bin/
RUN chmod +x /usr/local/bin/transform-php.py

# Create test directory
WORKDIR /test

# Create minimal lex and yacc files
RUN mkdir -p /test/Zend

# Create test files using RUN with echo
RUN echo 'TOKENS [;:,.|^&+-/*=%!~$<>?@\\[\\]{}()]' > /test/Zend/zend_language_scanner.l && \
echo '' >> /test/Zend/zend_language_scanner.l && \
echo '<ST_IN_SCRIPTING>"class" { return T_CLASS; }' >> /test/Zend/zend_language_scanner.l && \
echo '<ST_IN_SCRIPTING>"function" { return T_FUNCTION; }' >> /test/Zend/zend_language_scanner.l && \
echo '<ST_IN_SCRIPTING>"return" { return T_RETURN; }' >> /test/Zend/zend_language_scanner.l && \
echo '<ST_IN_SCRIPTING>"if" { return T_IF; }' >> /test/Zend/zend_language_scanner.l && \
echo '<ST_IN_SCRIPTING>"else" { return T_ELSE; }' >> /test/Zend/zend_language_scanner.l && \
echo '<ST_IN_SCRIPTING>"foreach" { return T_FOREACH; }' >> /test/Zend/zend_language_scanner.l && \
echo '<ST_IN_SCRIPTING>"as" { return T_AS; }' >> /test/Zend/zend_language_scanner.l && \
echo '<ST_IN_SCRIPTING>"echo" { return T_ECHO; }' >> /test/Zend/zend_language_scanner.l && \
echo '<ST_IN_SCRIPTING>"new" { return T_NEW; }' >> /test/Zend/zend_language_scanner.l && \
echo '<ST_IN_SCRIPTING>"public" { return T_PUBLIC; }' >> /test/Zend/zend_language_scanner.l && \
echo '<ST_IN_SCRIPTING>"private" { return T_PRIVATE; }' >> /test/Zend/zend_language_scanner.l

RUN echo '%token T_CLASS "class"' > /test/Zend/zend_language_parser.y && \
echo '%token T_FUNCTION "function"' >> /test/Zend/zend_language_parser.y && \
echo '%token T_RETURN "return"' >> /test/Zend/zend_language_parser.y && \
echo '%token T_IF "if"' >> /test/Zend/zend_language_parser.y && \
echo '%token T_ELSE "else"' >> /test/Zend/zend_language_parser.y && \
echo '%token T_FOREACH "foreach"' >> /test/Zend/zend_language_parser.y && \
echo '%token T_AS "as"' >> /test/Zend/zend_language_parser.y && \
echo '%token T_ECHO "echo"' >> /test/Zend/zend_language_parser.y && \
echo '%token T_NEW "new"' >> /test/Zend/zend_language_parser.y && \
echo '%token T_PUBLIC "public"' >> /test/Zend/zend_language_parser.y && \
echo '%token T_PRIVATE "private"' >> /test/Zend/zend_language_parser.y

# Copy test PHP file from host
COPY test-files/test.php /test/test.php

# Create test script
COPY test-symbol-scrambling-docker.sh /test/run-test.sh
RUN chmod +x /test/run-test.sh

ENV PHP_SRC_PATH=/test

CMD ["/test/run-test.sh"]
223 changes: 223 additions & 0 deletions SYMBOL_SCRAMBLING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,223 @@
# Symbol Scrambling Implementation

This branch (`archis/scramble-symbols`) extends the PHP encrypted execution scrambler to include **symbol scrambling** in addition to keyword scrambling.

## What's New

### Expanded Symbol Set

The scrambler now handles a comprehensive set of PHP symbols:

- **Brackets and Braces**: `(`, `)`, `[`, `]`, `{`, `}`
- **Separators**: `;`, `,`, `:`
- **Operators**: `-`, `+`, `=`, `%`
- **Bitwise/Logical**: `~`, `^`, `&`, `|`, `!`
- **Other**: `@` (error suppression)

### Excluded Symbols

Some symbols cannot be scrambled due to tokenization issues:

- `[` - Causes variable parsing issues in strings (currently included but may need refinement)
- `.` - Causes decimal number issues
- `>`, `<`, `?` - Cause PHP tag issues
- `$` - Causes variable issues
- `/`, `*` - Cause comment issues

## Changes Made

### 1. dictionaryHandler.go

**Expanded symbol set**:
```go
var symbolChars = [...]string{
"(", ")", "[", "]", "{", "}", // Brackets and braces
";", ",", ":", // Separators
"-", "+", "=", "%", // Operators (safe subset)
"~", "^", "&", "|", "!", // Bitwise and logical
"@", // Error suppression
}
var specialChars = []string{"(", ")", "[", "]", "{", "}", ";"}
```

**Enhanced permutation safety**:
```go
func permutationGen() {
// Avoids problematic mappings like:
// - ( → ) or ) → (
// - [ → ] or ] → [
// - { → } or } → {
// - Cross-type mappings (e.g., ( → [)
}
```

### 2. scrambler.go

**Updated TOKENS pattern** to include new symbols:
```go
const tokensPattern = "TOKENS [;:,.|^&+-/*=%!~$<>?@\\[\\]{}()]"
```

### 3. transform-php.py

**Two-pass transformation**:
1. **First pass**: Transform multi-character keywords (word-boundary safe)
2. **Second pass**: Transform single-character symbols (NOT inside strings)

The second pass carefully avoids transforming symbols inside quoted strings:
```python
# Split content into code and strings, transform only code parts
# Handles escape sequences properly
# Preserves string literals unchanged
```

### 4. run-scrambler.sh

**Enable symbol scrambling** by default on this branch:
```bash
/usr/local/bin/php-scrambler --chars
```

## Test Results

### Test Output

Running the test container produces:

```
Symbol transformations:
{ (open brace): 8 -> 1
} (close brace): 8 -> 4
( (open paren): 8 -> 0
) (close paren): 8 -> 10
[ (open bracket): 1 -> 0
] (close bracket): 1 -> 0
; (semicolon): 10 -> 8

✓ SUCCESS: 4 symbol types were scrambled!
```

### Example Dictionary

```json
{
"!": "[",
"%": "(",
"(": "^",
")": ",",
",": "!",
";": ")",
"[": "{",
"]": ":",
"{": ";",
"}": "-",
"class": "NlMIKXpLIF",
"function": "gctYobNePm",
"return": "EqCVEUrH",
...
}
```

### Example Transformation

**Original PHP**:
```php
class TestClass {
public function calculate($a, $b) {
$result = $a + $b;
if ($result > 10) {
return $result * 2;
}
}
}
```

**Scrambled PHP**:
```php
NlMIKXpLIF TestClass ;
jupqoZ gctYobNePm calculate^$a! $b, ;
$result } $a | $b)
dTQdiuZrLFgFA ^$result > 10, ;
EqCVEUrH $result * 2)
-
-
-
```

## Testing Locally

To test symbol scrambling locally:

```bash
# Build test image
docker build -t test-symbol-scrambling:local -f Dockerfile.test-symbols .

# Run test
docker run --rm test-symbol-scrambling:local
```

The test will:
1. Generate a scrambled dictionary with symbols
2. Transform lex/yacc files
3. Transform a test PHP file
4. Verify symbol transformations worked
5. Show before/after comparison

## Integration Notes

### For Production Use

To enable symbol scrambling in the main encrypted-execution image:

1. Merge this branch to main
2. Update `run-scrambler.sh` to use `--chars` flag
3. Rebuild PHP after scrambling (already handled by `recompile-php.sh`)
4. Update PEAR transformation to handle symbol mappings

### Potential Issues

1. **PEAR Compatibility**: Some PEAR files may have issues with symbol scrambling
2. **String Literals**: Symbols in strings are preserved, but complex heredocs may need testing
3. **Comments**: Symbols in comments are currently transformed (could be refined)
4. **Regular Expressions**: Regex patterns with symbols will be affected

### Future Improvements

1. **Exclude comments**: Don't transform symbols in `//` and `/* */` comments
2. **Heredoc/Nowdoc**: Better handling of heredoc/nowdoc strings
3. **Regex detection**: Preserve symbols in regex patterns
4. **Per-file control**: Allow disabling symbol scrambling for specific files
5. **Symbol validation**: Ensure scrambled PHP is still syntactically valid

## Architecture

The symbol scrambling works in three stages:

### Stage 1: Dictionary Generation (scrambler.go)
- Generates random symbol mappings
- Ensures no problematic mappings (e.g., `(` → `)`)
- Saves to `/var/lib/encrypted-execution/token-map.json`

### Stage 2: Lex/Yacc Transformation (scrambler.go)
- Updates TOKENS definition in lex file
- Transforms keywords in both files
- Creates scrambled PHP parser

### Stage 3: PHP File Transformation (transform-php.py)
- First pass: Transform keywords
- Second pass: Transform symbols (excluding strings)
- Preserves functionality while obfuscating structure

## Status

- ✅ Symbol scrambling implemented
- ✅ Local testing successful
- ✅ Dictionary generation works
- ✅ Lex/yacc transformation works
- ✅ PHP file transformation works
- ⏸️ Full integration testing pending
- ⏸️ PEAR compatibility testing pending

## Branch Status

This branch is for **local testing only** and has **not been pushed to GitHub** as requested.
Loading