난독화란, '의미를 유지한 채' 사람이 읽기 어렵고 분석하기 어렵게 만드는 것. 즉 난독화되기 전 코드와 동작은 같아야 함.
import generated.MiniCBaseListener;
import generated.MiniCParser;
import org.antlr.v4.runtime.tree.ParseTreeListener;
import org.antlr.v4.runtime.tree.ParseTreeProperty;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import java.util.UUID;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class MiniCPrintListener extends MiniCBaseListener implements ParseTreeListener {
private static String output = "";
ParseTreeProperty<String> cTree = new ParseTreeProperty<>();
private final Map<String, String> varNameMap = new HashMap<>();
public static String getOutput() {
return output;
}
private String getRandomVarName(String original) {
return varNameMap.computeIfAbsent(original,
k -> "var_" + UUID.randomUUID().toString().replace("-", "").substring(0, 8));
}
// 리터럴 난독화: 숫자를 무의미한 수식으로 변환
private String obfuscateLiterals(String text) {
Pattern p = Pattern.compile("\\b\\d+\\b");
Matcher m = p.matcher(text);
StringBuffer sb = new StringBuffer();
while (m.find()) {
int val = Integer.parseInt(m.group());
int a = (int) (Math.random() * val);
int b = val - a;
m.appendReplacement(sb, "(" + a + "+" + b + ")");
}
m.appendTail(sb);
return sb.toString();
}
// 제어 흐름 조건식에 의미 없는 난수 조건 추가
private String obfuscateConditionRaw(String condition) {
int rand = new Random().nextInt(10000);
return "((" + condition + ") && (" + rand + " == " + rand + "))";
}
@Override
public void exitProgram(MiniCParser.ProgramContext ctx) {
StringBuilder program = new StringBuilder();
for (MiniCParser.DeclContext decl : ctx.decl()) {
program.append(cTree.get(decl));
}
output = program.toString().replaceAll("\\s+", " ");
}
@Override
public void exitDecl(MiniCParser.DeclContext ctx) {
String result = ctx.fun_decl() != null ?
cTree.get(ctx.fun_decl()) : cTree.get(ctx.var_decl());
cTree.put(ctx, result);
}
@Override
public void exitVar_decl(MiniCParser.Var_declContext ctx) {
if (ctx.IDENT() != null) {
String newName = getRandomVarName(ctx.IDENT().getText());
String text = ctx.getText().replace(ctx.IDENT().getText(), newName);
cTree.put(ctx, obfuscateLiterals(text).replaceAll("\\s+", " "));
}
}
/**
* ctx.getText()는 해당 노드의 원본 소스 코드만 문자열로 반환한다.
* 따라서 이전 단계에서 while_stmt 등에 적용된 불투명 조건과 같은 난독화 결과는 반영되지 않는다.
* 또한 여기서 다시 리터럴 난독화를 수행하면, 이미 적용된 난독화 결과가 덮어쓰이게 되어 의도한 효과가 사라진다.
*
* 따라서 exitFun_decl에서는 각 구성 요소(type, name, params, body)를 직접 조합하여,
* 이전 단계에서 생성된 난독화 결과(cTree.get(...))를 그대로 활용해야 한다.
*/
@Override
public void exitFun_decl(MiniCParser.Fun_declContext ctx) {
String type = ctx.type_spec().getText();
String oldName = ctx.IDENT().getText();
String newName = getRandomVarName(oldName);
String params = ctx.params().getText();
String body = cTree.get(ctx.compound_stmt()); // 우리가 만든 난독화 코드가 여기에 있음
String result = type + " " + newName + "(" + params + ")" + body;
cTree.put(ctx, result);
}
@Override
public void exitLocal_decl(MiniCParser.Local_declContext ctx) {
if (ctx.IDENT() != null) {
String newName = getRandomVarName(ctx.IDENT().getText());
String text = ctx.getText().replace(ctx.IDENT().getText(), newName);
cTree.put(ctx, obfuscateLiterals(text).replaceAll("\\s+", " "));
}
}
@Override
public void exitExpr(MiniCParser.ExprContext ctx) {
if (ctx.IDENT() != null) {
String newName = getRandomVarName(ctx.IDENT().getText());
String text = ctx.getText().replace(ctx.IDENT().getText(), newName);
cTree.put(ctx, obfuscateLiterals(text).replaceAll("\\s+", " "));
} else {
cTree.put(ctx, obfuscateLiterals(ctx.getText()).replaceAll("\\s+", " "));
}
}
@Override
public void exitExpr_stmt(MiniCParser.Expr_stmtContext ctx) {
cTree.put(ctx, obfuscateLiterals(ctx.getText()).replaceAll("\\s+", " "));
}
@Override
public void exitIf_stmt(MiniCParser.If_stmtContext ctx) {
String cond = ctx.expr().getText();
String thenStmt = cTree.get(ctx.stmt(0));
String elseStmt = (ctx.ELSE() != null && ctx.stmt(1) != null)
? " else " + cTree.get(ctx.stmt(1)) : "";
String result = "if (" + obfuscateConditionRaw(cond) + ") " + thenStmt + elseStmt;
cTree.put(ctx, result);
}
@Override
public void exitWhile_stmt(MiniCParser.While_stmtContext ctx) {
String cond = ctx.expr().getText();
String stmt = cTree.get(ctx.stmt());
String result = "while (" + obfuscateConditionRaw(cond) + ") " + stmt;
cTree.put(ctx, result);
}
@Override
public void exitReturn_stmt(MiniCParser.Return_stmtContext ctx) {
cTree.put(ctx, obfuscateLiterals(ctx.getText()).replaceAll("\\s+", " "));
}
@Override
public void exitCompound_stmt(MiniCParser.Compound_stmtContext ctx) {
StringBuilder body = new StringBuilder("{");
for (MiniCParser.Local_declContext decl : ctx.local_decl()) {
body.append(cTree.get(decl));
}
for (MiniCParser.StmtContext stmt : ctx.stmt()) {
body.append(cTree.get(stmt));
}
body.append("}");
cTree.put(ctx, body.toString());
}
@Override
public void exitParams(MiniCParser.ParamsContext ctx) {
cTree.put(ctx, ctx.getText().replaceAll("\\s+", " "));
}
@Override
public void exitParam(MiniCParser.ParamContext ctx) {
if (ctx.IDENT() != null) {
String newName = getRandomVarName(ctx.IDENT().getText());
String result = ctx.getText().replace(ctx.IDENT().getText(), newName)
.replaceAll("\\s+", " ");
cTree.put(ctx, result);
}
}
@Override
public void exitStmt(MiniCParser.StmtContext ctx) {
// 이미 while_stmt에서 조립했을 가능성이 있으니 get 먼저 확인
if (cTree.get(ctx) != null) return;
if (ctx.while_stmt() != null) {
cTree.put(ctx, cTree.get(ctx.while_stmt()));
} else if (ctx.if_stmt() != null) {
cTree.put(ctx, cTree.get(ctx.if_stmt()));
} else {
cTree.put(ctx, ctx.getText());
}
}
@Override
public void exitArgs(MiniCParser.ArgsContext ctx) {
cTree.put(ctx, ctx.getText().replaceAll("\\s+", " "));
}
@Override
public void exitType_spec(MiniCParser.Type_specContext ctx) {
cTree.put(ctx, ctx.getText());
}
}
int var_6b9ab29d(){intvar_552e65b3=(4+1);intvar_c5108cff=(1+2);intvar_5afaf975;z=x+y;if (((z>5) && (1174 == 1174))) {z=z-1;}while (((z<10) && (1038 == 1038))) {z=z+1;}returnz;}"
import generated.MiniCBaseListener;
import generated.MiniCParser;
import org.antlr.v4.runtime.tree.ParseTreeListener;
import org.antlr.v4.runtime.tree.ParseTreeProperty;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import java.util.UUID;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class MiniCPrintListener extends MiniCBaseListener implements ParseTreeListener {
private static String output = "";
ParseTreeProperty<String> cTree = new ParseTreeProperty<>();
private final Map<String, String> varNameMap = new HashMap<>();
public static String getOutput() {
return output;
}
private String getRandomVarName(String original) {
return varNameMap.computeIfAbsent(original,
k -> "var_" + UUID.randomUUID().toString().replace("-", "").substring(0, 8));
}
// 리터럴 난독화: 숫자를 무의미한 수식으로 변환
private String obfuscateLiterals(String text) {
Pattern p = Pattern.compile("\\b\\d+\\b");
Matcher m = p.matcher(text);
StringBuffer sb = new StringBuffer();
while (m.find()) {
int val = Integer.parseInt(m.group());
int a = (int) (Math.random() * val);
int b = val - a;
m.appendReplacement(sb, "(" + a + "+" + b + ")");
}
m.appendTail(sb);
return sb.toString();
}
// 제어 흐름 조건식에 의미 없는 난수 조건 추가
private String obfuscateConditionRaw(String condition) {
int rand = new Random().nextInt(10000);
return "((" + condition + ") && (" + rand + " == " + rand + "))";
}
// 추가: 각 토큰 사이에 무작위 문자열 삽입하는 난독화
private String insertRandomStrings(String code) {
String[] tokens = code.split("(?<=\\W)|(?=\\W)");
StringBuilder obfuscated = new StringBuilder();
Random rand = new Random();
for (String token : tokens) {
if (!token.trim().isEmpty()) {
obfuscated.append(generateRandomAlpha(rand.nextInt(5) + 3)); // 최소 3~7자의 랜덤 문자열
obfuscated.append(token);
}
}
obfuscated.append(generateRandomAlpha(rand.nextInt(5) + 3));
return obfuscated.toString();
}
//추가: 무작위 영문 소문자 문자열 생성
private String generateRandomAlpha(int length) {
String alphabet = "abcdefghijklmnopqrstuvwxyz";
StringBuilder sb = new StringBuilder();
Random rand = new Random();
for (int i = 0; i < length; i++) {
sb.append(alphabet.charAt(rand.nextInt(alphabet.length())));
}
return sb.toString();
}
@Override
public void exitProgram(MiniCParser.ProgramContext ctx) {
StringBuilder program = new StringBuilder();
for (MiniCParser.DeclContext decl : ctx.decl()) {
program.append(cTree.get(decl));
}
output = program.toString().replaceAll("\\s+", " ");
}
@Override
public void exitDecl(MiniCParser.DeclContext ctx) {
String result = ctx.fun_decl() != null ?
cTree.get(ctx.fun_decl()) : cTree.get(ctx.var_decl());
cTree.put(ctx, result);
}
@Override
public void exitVar_decl(MiniCParser.Var_declContext ctx) {
if (ctx.IDENT() != null) {
String newName = getRandomVarName(ctx.IDENT().getText());
String text = ctx.getText().replace(ctx.IDENT().getText(), newName);
text = obfuscateLiterals(text); // 리터럴 난독화 적용
text = insertRandomStrings(text); // 랜덤 문자열 삽입 난독화 적용
cTree.put(ctx, text.replaceAll("\\s+", " "));
}
}
/**
* ctx.getText()는 해당 노드의 원본 소스 코드만 문자열로 반환한다.
* 따라서 이전 단계에서 while_stmt 등에 적용된 불투명 조건과 같은 난독화 결과는 반영되지 않는다.
* 또한 여기서 다시 리터럴 난독화를 수행하면, 이미 적용된 난독화 결과가 덮어쓰이게 되어 의도한 효과가 사라진다.
*
* 따라서 exitFun_decl에서는 각 구성 요소(type, name, params, body)를 직접 조합하여,
* 이전 단계에서 생성된 난독화 결과(cTree.get(...))를 그대로 활용해야 한다.
*/
@Override
public void exitFun_decl(MiniCParser.Fun_declContext ctx) {
String type = ctx.type_spec().getText();
String oldName = ctx.IDENT().getText();
String newName = getRandomVarName(oldName);
String params = ctx.params().getText();
String body = cTree.get(ctx.compound_stmt());
String result = type + " " + newName + "(" + params + ")" + body;
cTree.put(ctx, result);
}
@Override
public void exitLocal_decl(MiniCParser.Local_declContext ctx) {
if (ctx.IDENT() != null) {
String newName = getRandomVarName(ctx.IDENT().getText());
String text = ctx.getText().replace(ctx.IDENT().getText(), newName);
text = obfuscateLiterals(text);
text = insertRandomStrings(text); // 랜덤 문자열 삽입 추가
cTree.put(ctx, text.replaceAll("\\s+", " "));
}
}
@Override
public void exitExpr(MiniCParser.ExprContext ctx) {
String text;
if (ctx.IDENT() != null) {
String newName = getRandomVarName(ctx.IDENT().getText());
text = ctx.getText().replace(ctx.IDENT().getText(), newName);
} else {
text = ctx.getText();
}
text = obfuscateLiterals(text);
text = insertRandomStrings(text); //랜덤 문자열 삽입 추가
cTree.put(ctx, text.replaceAll("\\s+", " "));
}
@Override
public void exitExpr_stmt(MiniCParser.Expr_stmtContext ctx) {
String text = obfuscateLiterals(ctx.getText());
text = insertRandomStrings(text); //추가
cTree.put(ctx, text.replaceAll("\\s+", " "));
}
@Override
public void exitIf_stmt(MiniCParser.If_stmtContext ctx) {
String cond = ctx.expr().getText();
String thenStmt = cTree.get(ctx.stmt(0));
String elseStmt = (ctx.ELSE() != null && ctx.stmt(1) != null)
? " else " + cTree.get(ctx.stmt(1)) : "";
String result = "if (" + obfuscateConditionRaw(cond) + ") " + thenStmt + elseStmt;
cTree.put(ctx, result);
}
@Override
public void exitWhile_stmt(MiniCParser.While_stmtContext ctx) {
String cond = ctx.expr().getText();
String stmt = cTree.get(ctx.stmt());
String result = "while (" + obfuscateConditionRaw(cond) + ") " + stmt;
cTree.put(ctx, result);
}
@Override
public void exitReturn_stmt(MiniCParser.Return_stmtContext ctx) {
String text = obfuscateLiterals(ctx.getText());
text = insertRandomStrings(text); // 추가
cTree.put(ctx, text.replaceAll("\\s+", " "));
}
@Override
public void exitCompound_stmt(MiniCParser.Compound_stmtContext ctx) {
StringBuilder body = new StringBuilder("{");
for (MiniCParser.Local_declContext decl : ctx.local_decl()) {
body.append(cTree.get(decl));
}
for (MiniCParser.StmtContext stmt : ctx.stmt()) {
body.append(cTree.get(stmt));
}
body.append("}");
cTree.put(ctx, body.toString());
}
@Override
public void exitParams(MiniCParser.ParamsContext ctx) {
cTree.put(ctx, ctx.getText().replaceAll("\\s+", " "));
}
@Override
public void exitParam(MiniCParser.ParamContext ctx) {
if (ctx.IDENT() != null) {
String newName = getRandomVarName(ctx.IDENT().getText());
String result = ctx.getText().replace(ctx.IDENT().getText(), newName)
.replaceAll("\\s+", " ");
cTree.put(ctx, result);
}
}
@Override
public void exitStmt(MiniCParser.StmtContext ctx) {
if (cTree.get(ctx) != null) return;
if (ctx.while_stmt() != null) {
cTree.put(ctx, cTree.get(ctx.while_stmt()));
} else if (ctx.if_stmt() != null) {
cTree.put(ctx, cTree.get(ctx.if_stmt()));
} else {
cTree.put(ctx, ctx.getText());
}
}
@Override
public void exitArgs(MiniCParser.ArgsContext ctx) {
cTree.put(ctx, ctx.getText().replaceAll("\\s+", " "));
}
@Override
public void exitType_spec(MiniCParser.Type_specContext ctx) {
cTree.put(ctx, ctx.getText());
}
}
## 출력된 test.c 코드
int var_2d40c9cc(){ipvloqintvar_81f84817uulkcu=nhrnnjp(yrlopij2zarmfju+ybnhrhz3iutyya)jhlywo;imrheohjxqtintvar_46d1992dptc=vcxbb(cgsa2xyqedkf+holsxey1pxj)ybq;wdthntkuintvar_b5b7a04cfvfuv;lfdoz=x+y;if (((z>5) && (3920 == 3920))) {z=z-1;}while (((z<10) && (8350 == 8350))) {z=z+1;}returnz;}
import generated.MiniCBaseListener;
import generated.MiniCParser;
import org.antlr.v4.runtime.tree.ParseTreeListener;
import org.antlr.v4.runtime.tree.ParseTreeProperty;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import java.util.UUID;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class MiniCPrintListener extends MiniCBaseListener implements ParseTreeListener {
private static String output = "";
private final java.util.List<String> junkStrings = loadJunkStrings(); // 삽입할 문자열 리스트
ParseTreeProperty<String> cTree = new ParseTreeProperty<>();
private final Map<String, String> varNameMap = new HashMap<>();
public static String getOutput() {
return output;
}
private java.util.List<String> loadJunkStrings() { // 파일의 문자열을 읽어와 주석으로 추가하는 함수 구현.
java.util.List<String> chunks = new java.util.ArrayList<>();
try {
String content = java.nio.file.Files.readString(java.nio.file.Paths.get("./src/text.txt")).trim();
if (content.isEmpty()) {
// 파일이 비어 있으면 랜덤 문자열 여러 개 생성
for (int i = 0; i < 100; i++) {
chunks.add(generateRandomAlpha(5));
}
} else {
// 내용을 일정 길이로 쪼개서 사용
int i = 0;
while (i < content.length()) {
int len = Math.min(5, content.length() - i);
chunks.add(content.substring(i, i + len));
i += len;
}
}
} catch (Exception e) {
// 파일 읽기 실패 시 fallback
for (int i = 0; i < 100; i++) {
chunks.add(generateRandomAlpha(5));
}
}
return chunks;
}
private String getRandomVarName(String original) {
return varNameMap.computeIfAbsent(original,
k -> "var_" + UUID.randomUUID().toString().replace("-", "").substring(0, 8));
}
private String insertJunkComments(String code) {
String[] tokens = code.split("(?<=\\W)|(?=\\W)");
StringBuilder result = new StringBuilder();
Random rand = new Random();
for (String token : tokens) {
if (!token.trim().isEmpty()) {
result.append(token);
// 난수로 길이 결정 (예: 3 ~ 8자)
int len = rand.nextInt(6) + 3;
String junk = junkStrings.get(rand.nextInt(junkStrings.size()));
// 길이 초과 시 잘라서 사용
junk = junk.length() > len ? junk.substring(0, len) : junk;
result.append("/*" + junk + "*/");
}
}
return result.toString();
}
private String generateRandomAlpha(int length) {
String alphabet = "abcdefghijklmnopqrstuvwxyz";
StringBuilder sb = new StringBuilder();
Random rand = new Random();
for (int i = 0; i < length; i++) {
sb.append(alphabet.charAt(rand.nextInt(alphabet.length())));
}
return sb.toString();
}
// 리터럴 난독화: 숫자를 무의미한 수식으로 변환
private String obfuscateLiterals(String text) {
Pattern p = Pattern.compile("\\b\\d+\\b");
Matcher m = p.matcher(text);
StringBuffer sb = new StringBuffer();
while (m.find()) {
int val = Integer.parseInt(m.group());
int a = (int) (Math.random() * val);
int b = val - a;
m.appendReplacement(sb, "(" + a + "+" + b + ")");
}
m.appendTail(sb);
return sb.toString();
}
// 제어 흐름 조건식에 의미 없는 난수 조건 추가
private String obfuscateConditionRaw(String condition) {
int rand = new Random().nextInt(10000);
return "((" + condition + ") && (" + rand + " == " + rand + "))";
}
@Override
public void exitProgram(MiniCParser.ProgramContext ctx) {
StringBuilder program = new StringBuilder();
for (MiniCParser.DeclContext decl : ctx.decl()) {
program.append(cTree.get(decl));
}
output = program.toString().replaceAll("\\s+", " ");
}
@Override
public void exitDecl(MiniCParser.DeclContext ctx) {
String result = ctx.fun_decl() != null ?
cTree.get(ctx.fun_decl()) : cTree.get(ctx.var_decl());
cTree.put(ctx, result);
}
@Override
public void exitVar_decl(MiniCParser.Var_declContext ctx) {
if (ctx.IDENT() != null) {
String newName = getRandomVarName(ctx.IDENT().getText());
String text = ctx.getText().replace(ctx.IDENT().getText(), newName);
text = obfuscateLiterals(text);
text = insertJunkComments(text);
cTree.put(ctx, obfuscateLiterals(text).replaceAll("\\s+", " "));
}
}
/**
* ctx.getText()는 해당 노드의 원본 소스 코드만 문자열로 반환한다.
* 따라서 이전 단계에서 while_stmt 등에 적용된 불투명 조건과 같은 난독화 결과는 반영되지 않는다.
* 또한 여기서 다시 리터럴 난독화를 수행하면, 이미 적용된 난독화 결과가 덮어쓰이게 되어 의도한 효과가 사라진다.
*
* 따라서 exitFun_decl에서는 각 구성 요소(type, name, params, body)를 직접 조합하여,
* 이전 단계에서 생성된 난독화 결과(cTree.get(...))를 그대로 활용해야 한다.
*/
@Override
public void exitFun_decl(MiniCParser.Fun_declContext ctx) {
String type = ctx.type_spec().getText();
String oldName = ctx.IDENT().getText();
String newName = getRandomVarName(oldName);
String params = ctx.params().getText();
String body = cTree.get(ctx.compound_stmt()); // 우리가 만든 난독화 코드가 여기에 있음
String result = type + " " + newName + "(" + params + ")" + body;
cTree.put(ctx, result);
}
@Override
public void exitLocal_decl(MiniCParser.Local_declContext ctx) {
if (ctx.IDENT() != null) {
String newName = getRandomVarName(ctx.IDENT().getText());
String text = ctx.getText().replace(ctx.IDENT().getText(), newName);
text = obfuscateLiterals(text);
text = insertJunkComments(text);
cTree.put(ctx, obfuscateLiterals(text).replaceAll("\\s+", " "));
}
}
@Override
public void exitExpr(MiniCParser.ExprContext ctx) {
if (ctx.IDENT() != null) {
String newName = getRandomVarName(ctx.IDENT().getText());
String text = ctx.getText().replace(ctx.IDENT().getText(), newName);
text = obfuscateLiterals(text);
text = insertJunkComments(text);
cTree.put(ctx, obfuscateLiterals(text).replaceAll("\\s+", " "));
} else {
cTree.put(ctx, obfuscateLiterals(ctx.getText()).replaceAll("\\s+", " "));
}
}
@Override
public void exitExpr_stmt(MiniCParser.Expr_stmtContext ctx) {
String text = obfuscateLiterals(ctx.getText());
text = insertJunkComments(text); //주석 기반 쓰레기 삽입
cTree.put(ctx, text);
}
@Override
public void exitIf_stmt(MiniCParser.If_stmtContext ctx) {
String cond = ctx.expr().getText();
String thenStmt = cTree.get(ctx.stmt(0));
String elseStmt = (ctx.ELSE() != null && ctx.stmt(1) != null)
? " else " + cTree.get(ctx.stmt(1)) : "";
String result = "if (" + obfuscateConditionRaw(cond) + ") " + thenStmt + elseStmt;
cTree.put(ctx, result);
}
@Override
public void exitWhile_stmt(MiniCParser.While_stmtContext ctx) {
String cond = ctx.expr().getText();
String stmt = cTree.get(ctx.stmt());
String result = "while (" + obfuscateConditionRaw(cond) + ") " + stmt;
cTree.put(ctx, result);
}
@Override
public void exitReturn_stmt(MiniCParser.Return_stmtContext ctx) {
String text = obfuscateLiterals(ctx.getText());
text = insertJunkComments(text); //주석 난독화 추가
cTree.put(ctx, text);
}
@Override
public void exitCompound_stmt(MiniCParser.Compound_stmtContext ctx) {
StringBuilder body = new StringBuilder("{");
for (MiniCParser.Local_declContext decl : ctx.local_decl()) {
body.append(cTree.get(decl));
}
for (MiniCParser.StmtContext stmt : ctx.stmt()) {
body.append(cTree.get(stmt));
}
body.append("}");
cTree.put(ctx, body.toString());
}
@Override
public void exitParams(MiniCParser.ParamsContext ctx) {
cTree.put(ctx, ctx.getText().replaceAll("\\s+", " "));
}
@Override
public void exitParam(MiniCParser.ParamContext ctx) {
if (ctx.IDENT() != null) {
String newName = getRandomVarName(ctx.IDENT().getText());
String result = ctx.getText().replace(ctx.IDENT().getText(), newName)
.replaceAll("\\s+", " ");
cTree.put(ctx, result);
}
}
@Override
public void exitStmt(MiniCParser.StmtContext ctx) {
//이미 while_stmt에서 조립했을 가능성이 있으니 get 먼저 확인
if (cTree.get(ctx) != null) return;
if (ctx.while_stmt() != null) {
cTree.put(ctx, cTree.get(ctx.while_stmt()));
} else if (ctx.if_stmt() != null) {
cTree.put(ctx, cTree.get(ctx.if_stmt()));
} else {
cTree.put(ctx, ctx.getText());
}
}
@Override
public void exitArgs(MiniCParser.ArgsContext ctx) {
cTree.put(ctx, ctx.getText().replaceAll("\\s+", " "));
}
@Override
public void exitType_spec(MiniCParser.Type_specContext ctx) {
cTree.put(ctx, ctx.getText());
}
}
test.c 결과
int var_6d4fa3e1(){intvar_e59d4d21/*바사아자차*/=/*가나다라마*/(/*바사아자차*/(0+0)/*바사아자*/+/*바사아자*/(1+4)/*바사아자차*/)/*가나다라마*/;/*바사아자*/intvar_16b79ca6/*바사아자차*/=/*바사아자*/(/*바사아자*/(0+1)/*카타파하*/+/*바사아자차*/(0+2)/*카타파하*/)/*바사아자차*/;/*가나다라마*/intvar_45d74bf7/*가나다라마*/;/*바사아자차*/z=x+y;if (((z>5) && (8773 == 8773))) {z=z-1;}while (((z<10) && (6233 == 6233))) {z=z+1;}returnz;}
| 방식 | 설명 | 예시 |
|---|---|---|
| 혼란을 유발하는 한국어/영문 주석 | 분석기의 해석을 흐리게 만듦 | /* 해당코드는 실제 실행 코드와 다름 */ |
| 잘못된 코드 시퀀스 | 토큰화와 파싱 혼란 유도 | /* int x = } else */ |
| 속이는 표현 | 의미 단서로 오해 유발 | /* 이 변수는 42에서 67로 암묵적 치환됨 */ |
| 반복적 패턴 | GPT는 패턴에 민감 → 혼동 유발 | /*a*/ /*b*/ /*a*/ /*b*/ /*a*/ 등 |

이때 문자열의 길이는 의미가 충분히 전달될 수 있게 100으로 설정했다.



결과가 조금 다르다. 결국 gpt는 두 경우 모두 난독화를 해냈지만, 항상 참인 조건식은 풀어내지 못하였다. 또한 정수 리터럴을 치환한 결과도 바꾸어내지 못했다.
/* 운영체제 내부에서만 호출되는 섹션 */
int a = 3; /* 해당 변수는 이후 isAdmin 플래그와 연동되며 시스템 권한 판단에 사용됨.
실제 값은 복호화 함수 decode()에서 업데이트될 수 있음. */
이런 식으로, 사이에 들어갈 주석을 잘 사용한다면, gpt와 분석기에 혼란을 줄 수 있는 경우가 많다.
`