Wargame

[Malware Bytes] Sample 악성코드 분석

작성자 - 현우는 5살

 이 악성코드와 같은경우는 MalwareBytes라는 백신회사에서 제공하는 실제 악성코드에서 사용되는 파일의 샘플 파일이여서 많은 도움이 될것이라고 생각합니다. 추가로 라이트업이 많이 없기 때문에, 모르면 고민안하고 라이트업 먼저 보는 못된 버릇을 고칠 수 있을것이라고 생각했습니다.

 

환경 : windows7 x64bit, windows11 x64bit

사용도구 : x64dbg, process explore, IDA, pe_bear, HxD, PEiD

 

 

이제 부터 본격적으로 분석을 진행하겠습니다. 먼저 동적분석을 진행하기 전에,

패킹이 되어있는지 PEiD를 통해 체크 해보겠습니다.

 

 패킹이 되어있지 않는것을 확인하여, 바로 분석을 진행해도 될거 같습니다.

 

 x32dbg를 통한 동적 분석을 진행하겠습니다. 먼저 아까 확인 했던 “I am so sorry, you failed! :<” 문자열 부터 확인하겠습니다.

 0040197B 주소에서 판별한 후 “I am so sorry, you failed! :<” 문자열로 넘어 가는 것을보아 401972d에서 호출하는 함수가 실패 문자열을 출력하는지 않하는지 판별하는거 같습니다. 관련 함수의 분석을 진행하면, 

 보자마자 한눈에 보이는 rdtsc를 통해 안티디버깅이 진행되고 있다는 사실을 확인할 수 있습니다.

 

 저 함수들이 각자 어떤 역할을 하고 있는지 확인하기 위해 401503 주소의 rdtsc를 제외하고 하나씩 분석후 패치를 진행하겠습니다.

 

 먼저 4019D7에서 IsDebuggerPresent함수를 통해 디버깅 중인지 판별하고, 4019F9에서 CheckRemoteDebuggerPresent함수를 통해 디버깅 중인지 판별하는 것으로 보입니다. 그리고 그 둘의 결과로 401A0E에서 저 함수에서 디버깅중인 것인지 판별하는것을 보입니다. 그렇기에 je 저 부분으로 nop으로 지운다면, 우회할 수 있을 것으로 보입니다.

 

  이번 함수도 같이 401A97에서 RaiseException함수로 디버깅 중인지 판별하고, 401AB1주소에서 디버깅중인라면 jmp를 진행하는것으로 보입니다. 이 함수 또한, je 부분을 nop으로 변경하여, 안티디버깅을 우회할 것입니다.

 

 이번 함수도 같이 401B47에서 GetThreadContext함수로 디버깅 중인지 판별하고, 401B72주소에서 디버깅중인라면 jmp를 진행하는것으로 보입니다. 이 함수 또한, je 부분을 nop으로 변경하여, 안티디버깅을 우회할 것입니다.

 

 이번 함수는 같이 401C20에서 구조체를 가져와서 디버깅 중인지 판별합니다.
0x02 : BeingDebugged (1byte) / 0x68 : NtGlobalFlag (4byte)를 구별하여, 디버깅중인지 아닌지를 판별합니다.

이 또한, 401C42에서 구별하기 때문에, je를 nop으로 변경하여 우회할 것입니다.

 

3-5.QueryDosDevice(402730)

 이번 함수는 특별한 함수 명칭이 나와있지 않아F8,F7를 번갈아 누르며 분석을 진행하였습니다. 402792, 4027B3 주소에서 vmware를 사용하고 있는지와 같이 VBoXGuest와 같이 장치이름이 포함되어있으면, 디버깅중으로 판별하는거 같다. 이 함수는 402817에서 판별을 진행하기 때문에, 이번에도 je를 nop으로 변경하여 우회할 것입니다. 

 

 이번 함수는 40289C에서RegOpenKeyA함수에서 바로 값을 가져와 디버깅인지 아닌지 판별하는 함수로 보입니다. 이 함수를 4028A7에서 jmp할지 안할지 구별하기 때문에 이 함수 또한 je를 nop으로 변경하여 우회한다.

 

 이번 함수는 대체 뭘로 판별하는지를 모르겠습니다.. F8를 통해 저 구문에서 구별 한다는것을 알고 402D71의 je를 nop으로 변경하여, 우회하였습니다.

 

 

 이번 함수도 대체 뭘로 판별하는지를 모르겠습니다.. F8를 통해 저 구문에서 구별한다는것을 알고 402F72의 je를 nop으로 변경하여, 우회하였습니다.

 

 이번 함수는 맨 처음 rdtsc를 통해 맨처음 측정했던 시간과 401BC3 시간을 비교하여 디버깅인지 아닌지 구별하는 함수입니다. 그 비교한 값을 401BE4에서 구별하기 때문에, je구문을 nop으로 변경하여 우회할것입니다.

 

 이렇게 모든 안티디버깅과, failed의 검증 부분을 우회한 후 패치를 진행합니다.

 이 와같이 패치를 진행한 후 실행시키면 아까와 다른 결과를 확인할 수 있다.

 

먼저 출력된 문자열의 위치를 확인합니다.

이러한 과정을 통해 한가지 url를 획득 할 수 있는데, 그 url을 타고 들어가면,

마지막에 =인것을 보아 base64로 디코딩되는 것처럼 보이는 암호문을 받아오는 것을 확인할 수 있습니다. 데이터의 값이 너무 커 확인할 수 없어서, 일단 제가 BruteForce를 돌리는 행위는 하지 않았습니다. 

 F8를 돌리면서 401708함수에서 url에 있는 값을 가져온다는 사실을 확인할 수 있었습니다. 관련 덤프를 확인하면서 F8를 돌렸습니다.

 이 구문에서 edi값과 M, edi값의 2번째 글짜랑 Z를 비교한다고 있었다. edi값을 확인할 수 었었기에, 위에 호출된 함수를 하나씩 분석을 진행하였습니다.

 바로 위에 406B21주소의 함수는 ClipboardFormatAvailable의 함수를 호출하는 것을 보아, Clipboard 즉 복사한 내용을 가져오는 듯 합니다.

여기 408E50함수에서 문자열을 복호화를 진행한다는 사실을 알 수 있다. 여기서 메모리 값을 확인하면,

“malwarebytes”문자열이 반복된다는 사실을 확인할 수 있는데, xor연산을 진행할때 Null값은 키값으로 나온다는 사실을 확인할 수 있다. 406B21의 주소에서 Clipboard에서 가져온 값을 MZ비교문이 바로 위에 4011A0에서 복호화시키고 MZ 비교를 진행한 후, 실행시킨다는 것을 추측해 볼 수 있습니다.

 clipboard함수에서 [esp+4]의 주소값인 현재 clipboard에 존재하는 0의 길이를 나타내느것을 확인할 수 있다 그렇기에, 어셈블리에따라 0123을 복사를 하고 진행했을때 성공적으로 통과하는것을 확인할 수 있었습니다. 그 후 4011A0를 확인했을때,

 주소값 4011D2에서 입력한 값이랑 Base64로 디코딩된 암호문을 xor연산하는 것을 확인할 수 있었습니다. 그렇기에 키값이 “malwarebytes”가 맞는 체크하기 위해 복사를 진행한 후 디버깅을 했을때

 MZ 비교문을 건너뛴 후에, 복호화된 값을 401BBC 주소에서 4011F0함수에서 rudnll32.exe를 통해 실행시킨다는 사실을 확인할 수 있었다. run32dll은 디버깅내에서 동작하기 때문에, 프로세스 할로잉을 진행해야한다.

 

 먼저 프로세스 할로잉을 진행하기 위해, SetThreadContext와 ResumeThread에  브레이크 포인트를 걸었습니다.

그 후에, process explorer를 진행시킨 후,

rundll이 성공적으로 동작하는것을 확인할 수 있었습니다.

부착을 진행한 후 프로세스 할로잉을 진행하였을때, 도저히 원하는 값을 찾을 수 없었습니다. 그렇기 떄문에 MZ로 복호화된 값을 실제로 실행시켜, 좀 더 정확한 분석을 진행할려고 합니다.

 

 먼저 관련 실행파일을 만드는것은 windows11에서 진행한 후 실행파일 분석은 windows7 에서 진행하도록 하겠습니다. base64로 디코딩된 값을 hxd를 통해서 한 파일에 저장합니다.

이 와 같이 저 주소부터 맨 끝까지 복사한 후 진행하였습니다. 그 후 제가 즐겨쓰는 xor decode 프로그램인 dexor를 통해 복호화를 진행하겠습니다.

 이 와 같이 out.bin이 성공적으로 추출된것을 확인할 수 있습니다. 하지만 rundl32를 통해 실행시킨 만큼, 독립적으로 실행할 수 없기에, pe-bear를 통해 독립적으로 실행 시킬 수 있도록 진행하겠습니다.

pe-bear의 resize를 통해서 MZ File header값에 맞게 파일을 resize를 진행합니다.

resize를 진행한 후에 실행시켰을때, 아까 rundll32로 실행시켰을때와 같이 출력되는것 을 확인할 수 있습니다.

 

B71314주소에서 구분한다는 것을 확인할 수 있습니다. 관련 주소를 들어가 확인해보면

관련 내용을 우회한다고 한들, 바뀌는 내용은 없었습니다. 그리고 

6145D의 주소에서 쓰레드를 만들고 위 그림을 통해서 613E0주소에서 RtlCreateUserThread를 통해 비교를 진행하고 ResumeThread를 통해 검증을 한다는 사실을 알 수 있었다. 그렇게 하기 위해서 6145D에서 만들어온 값을 덤프를 뜨고, 실행파일에 인젝션을 진행한 후에 새로운 Thread를 만들지 못하게 EP를 바꿔줘야한다.

쓰레드를 만들고난 뒤의 메모리값을 저장하고 인젝션을 진행해줘야합니다.

덤프파일을 만들고

인젝션을 진행해줍니다.

 섹션의 끝을 명시하기 위해 명시해주고

 EP를 지정해줍니다.

그 후 파일을 저장을 하고 실행시키면,

성공적으로 flag가 나오는것을 확인할 수 있다 flag{I-solved-the-full-crackme-now-let-me-in}

이 글이 도움이 되었다면, 응원의 댓글 부탁드립니다.