Posts LLVM - 가상화 난독화를 수행하는 pass 제작 (3/4)
Post
Cancel

LLVM - 가상화 난독화를 수행하는 pass 제작 (3/4)

이번 목표 - 가상화 난독화를 수행하는 pass 작성하기

  • switch문을 이용하기 위한 for문 생성
  • switch문 생성

<< 이전 글에서 이어지는 내용

깃허브 소스코드 ✨

설명을 위해 작성한 코드는 이후에 변경된 것이 많아, 위의 깃허브 링크에서 확인하는 것이 좋음!

1. BasicBlock 나누기

img

색깔이 칠해진 부분은, 각 switch case에 들어갈 부분들이다.

우선 switch문을 반복하기 위한 for문을 구현하기 위해 BasicBlock을 for.cond/for.body/for.end/return 이렇게 네 부분으로 나누어준다.

이렇게 나눈 이유는 다음 목록에서 설명할 것이다.

구분 결과

img

2. for문을 위한 조건문을 만들기 및 블럭 간 분기 설정해주기

원래는 for문을 만들어주는 함수가 있으면 그 함수를 통해 for문을 생성하려고 했는데… LLVM 내에서 for문 자체를 만들 수 없는 것 같아 그냥 cond블럭에 branch를 만들고, body가 끝나면 다시 cond로 가서 end로 갈 것인지 다시 body를 반복하게 해 줄것인지 지정해 주면서 for문의 기능을 수행할 수 있도록 할 것이다.

각 BasicBlock에 대한 설명

  • condBB는 i값을 불러와 비교를 해 본 후 값에 따라 bodyBB 또는 endBB로 분기하도록 한다.
  • bodyBB는 이후에 switch로 변환할 부분이다. condBB로 돌아가는 분기와 returnBB로 바로 리턴해버리는 분기 두개가 있어서 둘 다 추가해버리면 오류가 발생하는데 (하나의 BasicBlock안에는 한 분기밖에 들어갈 수 없음) 어차피 switch 하면서 수정해 줄 것이다.
  • endBB는 for문이 끝났을 때 동작하는 것을 넣어줘야 한다. 사실 무조건 switch중간에 returnBB로 분기해서 여기로 도달할 일은 없지만 retval에 0을 넣어주고, returnBB로 분기하도록 한다.
  • returnBB는 값을 리턴하고 함수를 종료하는 BasicBlock이다.

img

근데 condBB에서 load하면서 문제가 생겼다. 불러올 변수 i가 다른 BasicBlock에 있어서 생기는 것 같아서 변수를 수정해줘야 할 것 같다. 일단 생각했던 코드를 작성해두고, 문제를 해결하면 고칠 것이다.

+ 다른 부분을 찾아보다가 문제를 해결했다. 문제를 해결한 방법은 값 할당 후 i변수에 값을 집어넣을 때 isVolatile값을 false로 지정한 것이었다. 오류에서 이상하게 volatile이 나오길래 뭔가 싶었는데…. 역시 빌더를 이용하는 게 안정적인 것 같다..

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
IRBuilder<> builder_cond(cond_bb);
Value *lhs = builder_cond.CreateLoad(var_i);
// i값을 condBB에 load
// ICmpInst *cond_instruction =
//     new ICmpInst(cond_bb, ICmpInst::ICMP_SGE, lhs, value_0,"");
Value *cond_instruction = builder_cond.CreateICmpSGE(lhs, value_0, "");
BranchInst::Create(body_bb, end_bb, cond_instruction, cond_bb);
// i의 값에 따라 bodyBB와 endBB로 분기하는 분기문 생성
BasicBlock::iterator to_remove_cond = cond_bb->begin();
Instruction *inst_to_remove_cond = &(*to_remove_cond);
inst_to_remove_cond->dropAllReferences();
inst_to_remove_cond->eraseFromParent();
// condBB의 원래 분기문을 없애면 condBB부분 완성

IRBuilder<> builder_end(end_bb);
builder_end.CreateStore(value_0, var_retval, /*isVolatile=*/false);
builder_end.CreateBr(return_bb);
BasicBlock::iterator to_remove_end= end_bb->begin();
Instruction *inst_to_remove_end = &(*to_remove_end);
inst_to_remove_end->dropAllReferences();
inst_to_remove_end->eraseFromParent();
// endBB에 0대입하는 것 넣어주기

결과 화면

img

3. switch문 생성

bodyBB에 switch문을 추가해준다. 이번에도 빌더를 이용하니까 편하다.

1
2
3
4
5
6
7
8
9
10
11
12
13
BasicBlock::iterator split_point_switch_start = body_bb->begin();
BasicBlock *case_bb =
    body_bb->splitBasicBlock(split_point_switch_start, "caseBB");

IRBuilder<> builder_body(body_bb);
Value *var_switch = builder_body.CreateLoad(var_i);
builder_body.CreateSwitch(var_switch, case_bb, 10);
builder_body.CreateBr(end_bb);
BasicBlock::iterator to_remove_body = body_bb->begin();
Instruction *inst_to_remove_body = &(*to_remove_body);
inst_to_remove_body->dropAllReferences();
inst_to_remove_body->eraseFromParent();
// switch문 추가

결과 화면

img

일단 switch문은 간단하게 생성할 수 있었다. (생성하는 것만 시도해 본 거라, 해당 코드는 오류를 뱉는다) 에필로그 블럭과 case블럭 생성하는 것을 다음 글에서 이어서 할 것이다.

다음 글에 계속 »

This post is licensed under CC BY 4.0 by the author.

Contents