CVE-2021-39863

  • ์˜ํ–ฅ์„ ๋ฐ›๋Š” ์ œํ’ˆ : https://helpx.adobe.com/security/products/acrobat/apsb21-55.html
    • Exploit์—๋Š” 32bit Adobe Acrobat Reader DC 21.005.20048.43252 ๋ฒ„์ „์„ ์‚ฌ์šฉํ•˜์˜€๋‹ค.
    • ํ•ด๋‹น ์ œํ’ˆ์€ ์•„๋ž˜ ๋งํฌ์—์„œ ๋‹ค์šด ๋ฐ›์„ ์ˆ˜ ์žˆ๋‹ค.
      • https://ardownload2.adobe.com/pub/adobe/reader/win/AcrobatDC/2100520048/AcroRdrDC2100520048_en_US.exe

1. ์ทจ์•ฝํ•œ ํ•จ์ˆ˜ ์ฐพ๊ธฐ

  • URL ์—ฐ๊ฒฐ ๊ณผ์ •์—์„œ ๋ฐœ์ƒํ•˜๋Š” ์ทจ์•ฝ์ ์ด๊ธฐ์— Adobe Acrobat Reader DC์˜ IA32.api๋ฅผ IDA๋กœ ์ •์  ๋ถ„์„์„ ์ง„ํ–‰ํ–ˆ๋‹ค.
  • ์ฐธ๊ณ ํ•œ Exploit ์ž๋ฃŒ์—๋Š” ์ทจ์•ฝํ•œ ํ•จ์ˆ˜ ์ฐพ๋Š” ๋ฐฉ๋ฒ•์ด ๋ˆ„๋ฝ๋˜์–ด 3๊ฐ€์ง€ ๋ฐฉ๋ฒ•์œผ๋กœ ์ทจ์•ฝํ•œ ํ•จ์ˆ˜๋ฅผ ์ฐพ์•˜๋‹ค.
  • ์ทจ์•ฝํ•œ ํ•จ์ˆ˜๋ฅผ ์ฐพ์€ ๋ฐฉ๋ฒ•

    1) ์ƒํ˜ธ ์ฐธ์กฐ

     - [Exodus Blog](https://blog.exodusintel.com/2021/10/04/analysis-of-a-heap-buffer-overflow-vulnerability-in-adobe-acrobat-reader-dc-2/?utm_source=feedly&utm_medium=rss&utm_campaign=analysis-of-a-heap-buffer-overflow-vulnerability-in-adobe-acrobat-reader-dc-2)์—์„œ ํ™•์ธํ•œ ๊ฒฐ๊ณผ ์ทจ์•ฝํ•œ ํ•จ์ˆ˜๊ฐ€ ํ˜ธ์ถœํ•œ ํ•จ์ˆ˜๋Š” URL ์—ฐ๊ฒฐ์„ ์œ„ํ•ด `strncat` ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•œ๋‹ค.
    
    • strncat ํ•จ์ˆ˜๋Š” ์™ธ๋ถ€์—์„œ importํ•ด ์‚ฌ์šฉํ•œ๋‹ค.
      • ์™ธ๋ถ€์—์„œ importํ•œ ํ•จ์ˆ˜๋Š” ํ•ด๋‹น ํ•จ์ˆ˜์˜ ์ด๋ฆ„์„ .rdata ์˜์—ญ์— ์ €์žฅํ•ด ํ˜ธ์ถœํ•  ๋•Œ ์ด์šฉํ•œ๋‹ค.
    • [๊ทธ๋ฆผ 1]๊ณผ [๊ทธ๋ฆผ 2]์ฒ˜๋Ÿผ .rdata ์˜์—ญ์—์„œ "strncat" ๋ฌธ์ž์—ด์„ ์ฐพ์•„ ์ทจ์•ฝํ•œ ํ•จ์ˆ˜๊ฐ€ ๋‚˜์˜ฌ ๋•Œ๊นŒ์ง€ ์ƒํ˜ธ์ฐธ์กฐํ•˜์˜€๋‹ค.

    image [๊ทธ๋ฆผ 1] .rdata ์˜์—ญ์—์„œ "strncat" ๋ฌธ์ž์—ด์„ ํ™•์ธํ•˜๊ณ , strncat ํ•จ์ˆ˜์˜ ์ƒํ˜ธ ์ฐธ์กฐ ํ•จ์ˆ˜๋ฅผ ํ™•์ธํ•œ ๋ชจ์Šต

    image [๊ทธ๋ฆผ 2] [๊ทธ๋ฆผ 10]์—์„œ ์ฐพ์€ strncat ํ•จ์ˆ˜์˜ ์ƒํ˜ธ ์ฐธ์กฐ ํ•จ์ˆ˜์˜ ์ƒํ˜ธ ์ฐธ์กฐ ํ•จ์ˆ˜๋ฅผ ํ™•์ธํ•œ ๋ชจ์Šต


    2) OpCode ๊ฒ€์ƒ‰

    • ์ทจ์•ฝํ•œ ํ•จ์ˆ˜์—์„œ๋Š” UTF16-BE encoding์„ ํƒ์ง€ํ•˜๊ธฐ ์œ„ํ•ด UTF16-BE BOM ๊ฒ€์‚ฌ๋ฅผ ์ง„ํ–‰ํ•œ๋‹ค.
      ๋Œ€ํ‘œ์ ์œผ๋กœ 1 byte ๊ฐ’๊ณผ "\xFF" ๋น„๊ตํ•˜๋Š” ์—ฐ์‚ฐ์„ ์ˆ˜ํ–‰ํ•œ๋‹ค.
    • "\xFF"์™€ 1 byte ๋ ˆ์ง€์Šคํ„ฐ๋ฅผ ๋น„๊ตํ•˜๋Š” OP Code๋ฅผ ์–ป์–ด, ํ•ด๋‹น OP Code๊ฐ€ ์กด์žฌํ•˜๋Š” ํ•จ์ˆ˜๋ฅผ ํƒ์ƒ‰ํ•˜๋ฉฐ ์ทจ์•ฝํ•œ ํ•จ์ˆ˜๋ฅผ ์ฐพ์•˜๋‹ค.

    image [๊ทธ๋ฆผ 3] OpCode ๊ฒ€์‚ฌ๋กœ ์ทจ์•ฝํ•œ ํ•จ์ˆ˜๋ฅผ ์ฐพ์€ ๋ชจ์Šต


    4) IDC IDA Script ์ด์šฉ

    • Exodus ๋ธ”๋กœ๊ทธ๋ฅผ ํ›‘์–ด๋ณธ ๊ฒฐ๊ณผ, ์ทจ์•ฝํ•œ ํ•จ์ˆ˜๋Š” ๋งŽ์€ ๋ช…๋ น์„ ๋ณด์œ ํ•˜๊ณ  ์žˆ๋Š” ๊ฒƒ์„ ํ™•์ธํ•˜์˜€๋‹ค. ์ด๋ฅผ ํ† ๋Œ€๋กœ instruction ์ˆ˜๋กœ ํ•จ์ˆ˜๋ฅผ ํƒ์ƒ‰ํ•˜๋ฉด ์ทจ์•ฝํ•œ ํ•จ์ˆ˜๋ฅผ ์‰ฝ๊ฒŒ ์ฐพ์„ ์ˆ˜ ์žˆ์œผ๋ฆฌ๋ผ ํŒ๋‹จํ–ˆ๋‹ค.

    • IDA์˜ ๋‚ด์žฅ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์–ธ์–ด์ธ IDC๋กœ ํŠน์ • instruction ์ˆ˜ ์ด์ƒ์˜ ํ•จ์ˆ˜๋ฅผ ์ฐพ๋Š” script๋ฅผ ์ž‘์„ฑํ•ด ์ทจ์•ฝํ•œ ํ•จ์ˆ˜๋ฅผ ์ฐพ์•˜๋‹ค.

      #include <idc.idc>
            
      static main() {
        auto func, end, count, inst;
        func = 0;
        Message("================ START =================\n");
        for(func = NextFunction(func); func != BADADDR; func = NextFunction(func)) {
          if(func != -1) {
            end = GetFunctionAttr(func, FUNCATTR_END);
            count = 0;
            inst = func;
            while(inst < end) {
              count++;
              inst = FindCode(inst, SEARCH_DOWN | SEARCH_NEXT);
            }
            if(count > 400) {
              Message("%s contains %d instructions\n" , Name(func), count);
            }
          } else {
            //Message("No function found at location %x", func);
          }
        }
      }
    

    image [๊ทธ๋ฆผ 4] IDC IDA Script๋กœ ์ทจ์•ฝํ•œ ํ•จ์ˆ˜๋ฅผ ์ฐพ์€ ๋ชจ์Šต

2. ์ทจ์•ฝํ•œ ํ•จ์ˆ˜ ๋ถ„์„

์ทจ์•ฝํ•œ ํ•จ์ˆ˜๋ฅผ ๋””์ปดํŒŒ์ผํ•œ ์ฝ”๋“œ
__int16 __cdecl ExploitPoint(wchar_t *Source, CHAR *lpString, char *String, _DWORD *a4, int *a5)
{
  __int16 v5; // di
  wchar_t *concatURL_addr; // ebx
  CHAR *lpString_copy; // eax
  CHAR v8; // dl
  __int64 len_lpString; // rax
  wchar_t *Source_copy; // ecx
  __int64 len_Source; // rax
  int v12; // eax
  int totallen_Source; // eax
  int len_Source_notUTF; // eax
  CHAR *allocadr_Source; // eax
  wchar_t *v16; // ecx
  int totallen_lpString; // eax
  int len_lpString_notUTF; // eax
  CHAR *allocadr_lpString; // eax
  int v20; // eax
  int v21; // edx
  int v22; // edx
  _DWORD *v23; // eax
  int v24; // ecx
  int *v25; // eax
  int v26; // ecx
  int v27; // eax
  int v28; // ecx
  int v29; // eax
  wchar_t *v30; // ecx
  int v31; // eax
  int len_allocaddr; // eax
  int v33; // eax
  int v34; // ecx
  int v35; // edx
  wchar_t *v37; // [esp-4h] [ebp-F4h]
  unsigned int v38; // [esp-4h] [ebp-F4h]
  wchar_t *v39; // [esp-4h] [ebp-F4h]
  unsigned int v40; // [esp-4h] [ebp-F4h]
  unsigned int v41; // [esp-4h] [ebp-F4h]
  int v42[7]; // [esp+Ch] [ebp-E4h] BYREF
  int v43; // [esp+28h] [ebp-C8h]
  int v44; // [esp+2Ch] [ebp-C4h]
  int v45; // [esp+30h] [ebp-C0h]
  int v46; // [esp+34h] [ebp-BCh]
  wchar_t *v47; // [esp+38h] [ebp-B8h]
  __int64 v48; // [esp+3Ch] [ebp-B4h]
  int v49; // [esp+4Ch] [ebp-A4h]
  int v50[3]; // [esp+50h] [ebp-A0h] BYREF
  int v51; // [esp+5Ch] [ebp-94h]
  int v52; // [esp+60h] [ebp-90h]
  int v53; // [esp+64h] [ebp-8Ch]
  int v54; // [esp+68h] [ebp-88h]
  int v55; // [esp+6Ch] [ebp-84h]
  int v56; // [esp+70h] [ebp-80h]
  int v57; // [esp+74h] [ebp-7Ch]
  int v58; // [esp+78h] [ebp-78h]
  char *v59; // [esp+7Ch] [ebp-74h]
  __int64 v60; // [esp+80h] [ebp-70h]
  __int64 v61; // [esp+88h] [ebp-68h]
  int v62; // [esp+90h] [ebp-60h]
  int v63[3]; // [esp+94h] [ebp-5Ch] BYREF
  int v64; // [esp+A0h] [ebp-50h]
  int v65; // [esp+A4h] [ebp-4Ch]
  int v66; // [esp+A8h] [ebp-48h]
  int v67; // [esp+ACh] [ebp-44h]
  int v68; // [esp+B0h] [ebp-40h]
  int v69; // [esp+B4h] [ebp-3Ch]
  int v70; // [esp+B8h] [ebp-38h]
  int v71; // [esp+BCh] [ebp-34h]
  void *v72; // [esp+C0h] [ebp-30h]
  __int128 v73; // [esp+C4h] [ebp-2Ch]
  int v74; // [esp+D4h] [ebp-1Ch]
  int iMaxLength[2]; // [esp+D8h] [ebp-18h]
  LPCSTR allocadr_lpString_copy; // [esp+E0h] [ebp-10h]
  LPCSTR allocadr_Source_copy; // [esp+E4h] [ebp-Ch]
  int v78[2]; // [esp+E8h] [ebp-8h] BYREF

  allocadr_Source_copy = 0;
  allocadr_lpString_copy = 0;
  v5 = 1;
  *(_QWORD *)v78 = 0i64;
  *(_QWORD *)iMaxLength = 0i64;
  concatURL_addr = 0;
  v49 = 0;
  v62 = 0;
  v74 = 0;
  if(!a5) return 0;
  *a5 = 0;
  
  // [1-1] relative URL ๊ธธ์ด ์ธก์ •
  lpString_copy = lpString;
  if(lpString && *lpString && (v8 = lpString[1]) != 0 && *lpString == (CHAR)0xFE && v8 == (CHAR)0xFF) {
    len_lpString = ((__int64 (__cdecl *)(CHAR *))strlen_UTF16BE)(lpString);
    v78[1] = len_lpString;
    if ((HIDWORD(len_lpString)&(unsigned int)len_lpString) == -1) {
LABEL_9:
      *a5 = -2;
      return 0;
    }
    lpString_copy = lpString;
  } else {
    v78[1] = v78[0];
  }
  
  // [1-2] base URL ๊ธธ์ด ์ธก์ •
  Source_copy = Source;
  if(!Source || !lpString_copy || !String || !a4) {
    *a5 = -2;
    goto LABEL_86;
  }
  if(*(_BYTE *)Source != 0xFE) goto LABEL_25;
  if(*((_BYTE *)Source+1) == 0xFF) {
    len_Source = ((__int64 (__cdecl *)(wchar_t *))strlen_UTF16BE)(Source);
    iMaxLength[1] = len_Source;
    if((HIDWORD(len_Source)&(unsigned int)len_Source) == -1) goto LABEL_9;
    Source_copy = Source;
    v12 = iMaxLength[1];
  } else {
    v12 = iMaxLength[0];
  }
  if(*(_BYTE *)Source_copy == 0xFE && *((_BYTE *)Source_copy+1) == 0xFF) {
    totallen_Source = v12 + 2;
  } else {
LABEL_25:
    len_Source_notUTF = (int)custom_strlen((LPCSTR)Source_copy);
    Source_copy = v37;
    totallen_Source = len_Source_notUTF + 1;
  }
  iMaxLength[1] = totallen_Source;
  
  // [2-1] base URL์„ ์ƒˆ๋กœ์šด heap์— ์ €์žฅ
  allocadr_Source = (CHAR *)((int (__usercall *)@<eax>(wchar_t *@<ecx>, int, int))calloc_guess)(Source_copy, 1, totallen_Source);
  allocadr_Source_copy = allocadr_Source;
  if(!allocadr_Source) {
    *a5 = -7;
    return 0;
  }
  ((void (__usercall *)(unsigned int@<ecx>, wchar_t *, wchar_t *, int))custom_strncpy)(v38, (wchar_t *)allocadr_Source, Source, iMaxLength[1]);
  if(*lpString==(CHAR)0xFE && lpString[1]==(CHAR)0xFF) {
    totallen_lpString = v78[1] + 2;
  } else {
    len_lpString_notUTF = (int)custom_strlen(lpString);
    v16 = v39;
    totallen_lpString = len_lpString_notUTF + 1;
  }
  v78[1] = totallen_lpString;
  
  // [2-2] relative URL์„ ์ƒˆ๋กœ์šด heap์— ์ €์žฅ
  allocadr_lpString = (CHAR *)((int (__usercall *)@<eax>(wchar_t *@<ecx>, int, int))calloc_guess)(v16, 1, totallen_lpString);
  allocadr_lpString_copy = allocadr_lpString;
  if(!allocadr_lpString) {
    *a5 = -7;
LABEL_86:
    v5 = 0;
    goto LABEL_87;
  }
  ((void (__usercall *)(unsigned int@<ecx>, wchar_t *, wchar_t *, int))custom_strncpy)(v40, (wchar_t *)allocadr_lpString, (wchar_t *)lpString, v78[1]);
  if(!(unsigned __int16)check_modify_URL((int)allocadr_Source_copy, iMaxLength[1], a5) || !(unsigned __int16)check_modify_URL((int)allocadr_lpString_copy, v78[1], a5)) {
    goto LABEL_86;
  }
  
  // [3] URL ๊ด€๋ จ ์—ฐ์‚ฐ ์ˆ˜ํ–‰
  v20 = URLparse_process((CHAR *)allocadr_Source_copy, v42);
  if(v20 || (v20 = URLparse_process((CHAR *)allocadr_lpString_copy, v50)) != 0) {
    *a5 = v20;
    goto LABEL_86;
  }
  if(!*(_BYTE *)Source || (v21 = v42[0], v50[0] != 5) && v50[0] != v42[0]) {
    v35 = sub_25802FAC((int)v50);
    v23 = a4;
    v24 = v35 + 1;
    if(v35 + 1 > *a4) goto LABEL_44;
    *a4 = v35;
    v25 = v50;
    goto LABEL_82;
  }
  if(*lpString) {
    v26 = v55;
    v63[1] = v42[1];
    v63[2] = v42[2];
    v27 = v51;
    v63[0] = v42[0];
    v73 = 0i64;
    if(!v51 && !v53 && !v55) {
      if(sub_25803155(v50)) {
        v28 = v44;
        v64 = v42[3];
        v65 = v42[4];
        v66 = v42[5];
        v67 = v42[6];
        v29 = v43;
        if(v49 == 1) {
          v29 = v43 + 2;
          v28 = v44 - 1;
          v43 += 2;
          --v44;
        }
        v69 = v28;
        v68 = v29;
        v70 = v45;
        if(v58) {
          if (*v59 != '/') {
          
            // [4] ์—ฐ๊ฒฐ๋œ URL์„ ์ €์žฅํ•˜๊ธฐ ์œ„ํ•œ ์ƒˆ๋กœ์šด heap ํ• ๋‹น
            concatURL_addr = (wchar_t *)((int (__usercall *)@<eax>(wchar_t *@<ecx>, int, int))calloc_guess)((wchar_t *)(v58 + 1), 1, v58 + 1 + v46);
            if(!concatURL_addr) {
              v23 = a4;
              v24 = v58 + v46 + 1;
              goto LABEL_44;
            }
            if(v46) {
            
              // [5] base URL์„ [4]์—์„œ ํ• ๋‹นํ•œ heap memory์— ์ €์žฅ
              ((void (__usercall *)(unsigned int@<ecx>, wchar_t *, wchar_t *, int))custom_strncpy)(v41, concatURL_addr, v47, v46 + 1);
              if (*((_BYTE *)concatURL_addr + v46 - 1) != '/') {
                v31 = ((int (__usercall *)@<eax>(wchar_t *@<ecx>, char *, int))sub_25818D6E)(v30, (char *)concatURL_addr, '/');
                if(v31) *(_BYTE *)(v31 + 1) = 0;
                else *(_BYTE *)concatURL_addr = 0;
              }
            }
            
            // [6] relative URL์„ [5]์—์„œ ์ €์žฅํ•œ base URL ๋’ค์— ์ด์–ด ๋ถ™์ž„ : ์ทจ์•ฝ์  ๋ฐœ์ƒ
            if(v58) {
              len_allocaddr = (int)custom_strlen((LPCSTR)concatURL_addr);
              ((void (__usercall *)(uintptr_t@<ecx>, char *, char *, int))custom_strncat)(v58 + 1, (char *)concatURL_addr, v59, v58 + 1 + len_allocaddr);
            }
            
            sub_25802E0C((int)concatURL_addr, 0);
            v71 = (int)custom_strlen((LPCSTR)concatURL_addr);
            v72 = concatURL_addr;
            goto LABEL_75;
          }
          v71 = v58;
          v72 = v59;
        } else {
          v71 = v46;
          v72 = v47;
          if((_DWORD)v60) goto LABEL_75;
          *(_QWORD *)&v73 = v48;
        }
LABEL_74:
        if((_DWORD)v73) {
LABEL_77:
          if ( (int)v61 > 0 ) *((_QWORD *)&v73 + 1) = v61;
          v34 = sub_25802FAC((int)v63);
          if(v34+1 > *a4) {
            *a4 = v34 + 1;
            goto LABEL_45;
          }
          *a4 = v34;
          v25 = v63;
          goto LABEL_82;
        }
LABEL_75:
        if((int)v60 > 0) *(_QWORD *)&v73 = v60;
        goto LABEL_77;
      }
      v26 = v55;
      v21 = v42[0];
      v27 = v51;
    }
    v64 = v27;
    v65 = v52;
    v66 = v53;
    v67 = v54;
    v33 = v56;
    if(v62 == 1) {
      v26 += 2;
      v33 = v56 - 1;
      v55 = v26;
      --v56;
    }
    v69 = v33;
    v68 = v26;
    v71 = v58;
    v70 = v57;
    v72 = v59;
    if(v57) goto LABEL_75;
    v78[1] = 0;
    if(!sub_25802C93(v21, &v78[1])) goto LABEL_75;
    v70 = v78[1];
    goto LABEL_74;
  }
  v22 = sub_25802FAC((int)v42);
  v23 = a4;
  v24 = v22 + 1;
  if(v22+1 > *a4) {
LABEL_44:
    *v23 = v24;
LABEL_45:
    *a5 = -3;
    goto LABEL_86;
  }
  *a4 = v22;
  v25 = v42;
LABEL_82:
  sub_25803194((int)v25, String);
LABEL_87:
  if(allocadr_Source_copy)
    (*(void (__cdecl **)(LPCSTR))(dword_25824098 + 12))(allocadr_Source_copy);
  if(allocadr_lpString_copy)
    (*(void (__cdecl **)(LPCSTR))(dword_25824098 + 12))(allocadr_lpString_copy);
  if(concatURL_addr)
    (*(void (__cdecl **)(wchar_t *))(dword_25824098 + 12))(concatURL_addr);
  return v5;
}

Root Cause๋ฅผ ์ดํ•ดํ•˜๋Š” ๋ฐ ์•„๋ž˜์˜ ํ•จ์ˆ˜๋“ค์„ ์ดํ•ดํ•ด์•ผ ํ•œ๋‹ค.

  1. ExploitPoint() : ๋ถ„์„์˜ ์‹œ์ž‘ ํ•จ์ˆ˜
    • Parameter
      • _BYTE *Source : baseURL
      • _BYTE *lpString : relative URL
    • Exploit์— ํ•„์š”ํ•œ ๋ถ€๋ถ„๋งŒ ๋‚˜ํƒ€๋‚ด๋ฉด ํฌ๊ฒŒ ์•„๋ž˜์˜ ๋™์ž‘์„ ๊ฑฐ์นœ๋‹ค.
      1. URL ๊ธธ์ด ์ธก์ •

        [1-1] relative URL ๊ธธ์ด ์ธก์ • [1-2] base URL ๊ธธ์ด ์ธก์ •
      2. URL์„ heap์— ์ €์žฅ

        [2-1] base URL์„ ์ƒˆ๋กœ์šด heap์— ์ €์žฅ [2-2] relative URL์„ ์ƒˆ๋กœ์šด heap์— ์ €์žฅ
      3. URL ๊ด€๋ จ ์—ฐ์‚ฐ ์ˆ˜ํ–‰ (Exploit๊ณผ ์ง์ ‘์ ์ธ ์—ฐ๊ด€์€ ์—†๋‹ค.)

      4. ์—ฐ๊ฒฐ๋œ URL์„ ์ €์žฅํ•˜๊ธฐ ์œ„ํ•œ ์ƒˆ๋กœ์šด heap ํ• ๋‹น

      5. base URL์„ [4]์—์„œ ํ• ๋‹นํ•œ heap memory์— ์ €์žฅ

      6. relative URL์„ [5]์—์„œ ์ €์žฅํ•œ base URL ๋’ค์— ์ด์–ด ๋ถ™์ž„ : ์ทจ์•ฝ์  ๋ฐœ์ƒ


  2. strlen_UTF16BE : UTF16-BE encoding ๋ฌธ์ž์—ด์˜ ๊ธธ์ด๋ฅผ ๊ณ„์‚ฐํ•œ๋‹ค.
    • Parameter
      • char *string : ๊ธธ์ด๋ฅผ ๊ณ„์‚ฐํ•  UTF16-BE๋กœ encoding๋œ ๋ฌธ์ž์—ด
    • return value : Null Terminator๋ฅผ ์ œ์™ธํ•œ UTF16-BE URL์˜ byte ์ˆ˜
     int __cdecl strlen_UTF16BE(char *string)
     {
       char *p_string_i0; // eax
       char string_i1; // cl
       int length; // esi
       char string_i0; // bl
       char *p_string_i1; // eax
        
       p_string_i0 = string;
       if(!string || *string != -2 || string[1] != -1) return -1;
       string_i1 = 0;
       length = 0;
       do {
         string_i0 = *p_string_i0;
         p_string_i1 = p_string_i0 + 1;
         if(!p_string_i1) break;
         string_i1 = *p_string_i1;
         p_string_i0 = p_string_i1 + 1;
         if(!string_i0) goto LABEL_10;
         if(!string_i1) break;
         length += 2;
       } while ( p_string_i0 );
       if(string_i0) return -1;
     LABEL_10:
       if(!string_i1) return length;
       else return -1;
     }
    
  3. custom_strlen() : UTF16-BE์—์„œ๋„ ๋™์ž‘ํ•˜๋Š” strlen ํ•จ์ˆ˜์ด๋‹ค.
    • Parameter
      • LPCSTR lpString : UTF-16BE๋กœ encoding๋œ ๋ฌธ์ž์—ด์˜ ์ฃผ์†Œ (32 bit)
    • return value : Null Terminator๋ฅผ ์ œ์™ธํ•œ URL์˜ byte ์ˆ˜
     int __cdecl strlen_UTF16BE_(char *string)
     {
       char *v1; // ecx
       int i; // edx
       char v4; // al
        
       v1 = string;
       if(!string) return 0;
       for(i = 0; ; i += 2) {
         v4 = *v1;
         v1 += 2;
         if (!v4 && !*(v1-1)) break;
       }
       return i;
     }
    
  4. calloc_guess() : C์˜ calloc ํ•จ์ˆ˜์ด๋‹ค.
  5. custom_strncpy() : UTF16-BE์—์„œ๋„ ๋™์ž‘ํ•˜๋Š” strncpy ํ•จ์ˆ˜์ด๋‹ค.
    • Parameter
      • wchar_t *Destination : ๋ณต์‚ฌํ•  ์ฃผ์†Œ
      • wchar_t *Source : ๋ณต์‚ฌํ•  ๋ฌธ์ž์—ด(์˜ ์ฃผ์†Œ)
      • unsigned int iMaxLength : ๋ณต์‚ฌํ•  ๊ธธ์ด
    • return value : deststr (๋ณต์‚ฌํ•  ๊ณต๊ฐ„; ๋ณต์‚ฌ๋œ ์žฅ์†Œ)
     wchar_t *__cdecl custom_strncpy(wchar_t *Destination, wchar_t *Source, unsigned int iMaxLength)
     {
       wchar_t *result; // eax
       int pExceptionObject; // [esp+Ch] [ebp-4h] BYREF
        
       if(!Destination || !Source || !iMaxLength) {
         (*(void (__thiscall **)(_DWORD, int))(dword_258240A4 + 4))(*(_DWORD *)(dword_258240A4 + 4), 1073741827);
         pExceptionObject = 0;
         CxxThrowException(&pExceptionObject, (_ThrowInfo *)&_TI1H);
       }
       if(*(_BYTE *)Source == 0xFE && *((_BYTE *)Source+1) == 0xFF)
         return wcsncpy(Destination, Source, iMaxLength >> 1);
       result = (wchar_t *)lstrcpynA((LPSTR)Destination, (LPCSTR)Source, iMaxLength);
       *((_BYTE *)Destination + iMaxLength - 1) = 0;
       return result;
     }
    
  6. custom_strncat() : UTF16-BE์—์„œ๋„ ๋™์ž‘ํ•˜๋Š” strncat ํ•จ์ˆ˜์ด๋‹ค.
    • Parameter
      • char *Destination, char *Source, int maxlength
    • Destination ๋’ค์— Source๋ฅผ ๋ถ™์ž„
    • ์ •์ƒ์ ์ธ ๊ฒฝ์šฐ ๋‘ ๋ฒˆ์งธ if ๋ฌธ์„ ํ†ตํ•ด custom_strcat(Destination, Source); ํ˜ธ์ถœ
     int __cdecl custom_strncat(char *Destination, char *Source, int maxlength)
     {
       int result; // eax
       LPCSTR pExceptionObject; // [esp+10h] [ebp-4h] BYREF
        
       if(!Destination || !Source || !maxlength) {
         (*(void (__thiscall **)(_DWORD, int))(dword_258240A4 + 4))(*(_DWORD *)(dword_258240A4 + 4), 1073741827);
         pExceptionObject = 0;
         CxxThrowException(&pExceptionObject, (_ThrowInfo *)&_TI1H);
       }
       pExceptionObject = custom_strlen(Destination);
       if(&custom_strlen(Source)[(int)pExceptionObject] <= (const CHAR *)(maxlength-1)) {
         custom_strcat(Destination, Source);
         return 1;
       } else {
         strncat(Destination, Source, maxlength - (_DWORD)pExceptionObject - 1);
         result = 0;
         Destination[maxlength - 1] = 0;
       }
       return result;
     }
    

  7. custom_strcat() : UTF16-BE์—์„œ๋„ ๋™์ž‘ํ•ด์•ผ ํ•˜๋Š” strcat ํ•จ์ˆ˜๋กœ ์ง์ ‘์ ์œผ๋กœ ์ทจ์•ฝ์ ์ด ๋ฐœ์ƒํ•œ๋‹ค.
    • Parameter
      • LPSTR lpString1 : base URL
      • LPCSTR lpString2 : relative URL
    • base URL์ด UTF16-BE๋กœ encoding ๋˜์—ˆ์„ ๊ฒฝ์šฐ, base URL ๋’ค์— "\x00\x00"์ด ๋‚˜์˜ฌ ๋•Œ๊นŒ์ง€ relative URL์„ 2 byte ์”ฉ ๋ณต์‚ฌํ•œ๋‹ค.
      • ์ฆ‰, relative URL์ด UTF16-BE๋กœ encoding ๋˜์—ˆ๋‹ค๊ณ  ์ธ์‹ํ•˜๊ณ  ์—ฐ๊ฒฐ์„ ์ง„ํ–‰ํ•œ๋‹ค.
    • base URL์ด UTF16-BE๋กœ encoding ๋˜์ง€ ์•Š์•˜์„ ๊ฒฝ์šฐ, lstrcatA ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•ด "\x00"์ด ๋‚˜์˜ฌ ๋•Œ๊นŒ์ง€ base URL ๋’ค์— relative URL์„ 1 byte ์”ฉ ๋ณต์‚ฌํ•œ๋‹ค.
      • ์ฆ‰, relative URL๋„ UTF16-BE๋กœ encoding ๋˜์ง€ ์•Š์•˜๋‹ค๊ณ  ์ธ์‹ํ•˜๊ณ  ์—ฐ๊ฒฐ์„ ์ง„ํ–‰ํ•œ๋‹ค.
     LPSTR __cdecl custom_strcat(LPSTR lpString1, LPCSTR lpString2)
     {
       int len_lpString1; // eax
       LPCSTR p_lpString2_i2; // edx
       CHAR *concatpoint; // ecx
       CHAR lpString2_i2; // al
       CHAR lpString2_i3; // bl
       int pExceptionObject; // [esp+10h] [ebp-4h] BYREF
            
       if(!lpString1 || !lpString2) {
         (*(void (__thiscall **)(_DWORD, int))(dword_258240A4 + 4))(*(_DWORD *)(dword_258240A4 + 4), 1073741827);
         pExceptionObject = 0;
         CxxThrowException(&pExceptionObject, (_ThrowInfo *)&_TI1H);
       }
       if(*lpString1 == (CHAR)0xFE && lpString1[1] == (CHAR)0xFF) {
         len_lpString1 = (int)custom_strlen(lpString1);
         p_lpString2_i2 = lpString2 + 2;
         concatpoint = &lpString1[len_lpString1];
         do {
           do {
             lpString2_i2 = *p_lpString2_i2;
             p_lpString2_i2 += 2;
             *concatpoint = lpString2_i2;
             concatpoint += 2;
             lpString2_i3 = *(p_lpString2_i2 - 1);
             *(concatpoint - 1) = lpString2_i3;
           } while(lpString2_i2);
         } while(lpString2_i3);
       } else {
         lstrcatA(lpString1, lpString2);
       }
       return lpString1;
     }
    

3. Root Cause

image [๊ทธ๋ฆผ 5] Root Cause ๋ชจ์‹๋„

Adobe Root Cause.pdf

REFERENCE

[1] THE IDA PRO BOOK 2ND EDITION (Chris Eagle)