首页
论坛
专栏
课程

[原创]看雪CTF.TSRC 2018 团队赛第六题追凶者也WP

2018-12-13 11:29 1325

[原创]看雪CTF.TSRC 2018 团队赛第六题追凶者也WP

2018-12-13 11:29
1325

0、环境:win7 64bits

1、初步分析

    将可执行文件拖入Ida分析,可以看到WinMain()入口函数如下:
int __stdcall WinMain()
{
  sub_401280();
  return 0;
}
void sub_401280()
{
  ;
}

程序sub_401280()是一个空函数,看来有其他奥妙了。

2、 分析TLS( ThreadLocalStorage )

发现在Exports中有tlscallback,好了,我们首先看看在tls中做了什么?

HANDLE __stdcall TlsCallback_0(int a1, int a2, int a3)
{
  HANDLE result; // eax
  int Parameter; // [esp+Ch] [ebp-8h]
  int v5; // [esp+10h] [ebp-4h]

  result = (HANDLE)0xCCCCCCCC;
  Parameter = 0xCCCCCCCC;
  v5 = 0xCCCCCCCC;
  if ( a2 == 1 )
  {
    sub_401D50();
    InitializeCriticalSection(&CriticalSection);
    sub_401C10();
    result = CreateThread(0, 0, StartAddress, &Parameter, 0, 0);
  }
  return result;
}

  1. 我们首先分析sub_401D50()函数

int sub_401D50()
{
  signed int i; // [esp+0h] [ebp-18h]
  int v2[3]; // [esp+Ch] [ebp-Ch]

  v2[1] = 0xCCCCCCCC;
  v2[2] = 0xCCCCCCCC;
  v2[0] = 0xE9;
  *(int *)((char *)v2 + 1) = (char *)off_414014 - (char *)((_BYTE *)off_414018 + 4) - 5;    //组织jmp指令
  sub_4019B0(off_414018);
  for ( i = 0; i < 5; ++i )
    *((_BYTE *)off_414018 + i + 4) = *((_BYTE *)v2 + i);                                    //插入jmp指令                       
  return sub_4019E0(off_414018);
}
.data:00414014 off_414014      dd offset sub_401220    ; DATA XREF: sub_401D50+45↑r
.data:00414018 off_414018      dd offset sub_401280    ; DATA XREF: sub_401D50+3D↑r

可以看到:
全局变量off_414018存储着sub_401280()函数地址,而该函数就是 WinMain()中那个空函数地址。
全局变量off_414018存储着 sub_401220()
这里在 sub_401280()中插入了 sub_401220()函数调用。修改前后对比如下图:

sub_11220()函数如下:
void __noreturn sub_401220()
{
  HINSTANCE hInstance; // ST18_4

  hInstance = GetModuleHandleW(0);
  DialogBoxParamW(hInstance, (LPCWSTR)0x65, 0, DialogFunc, 0);
  exit(0);
}

我们暂时先放下TLS分析,看看DialogFunc()函数,在该函数里主要是调用了sub_401040()这个函数。
int __cdecl sub_401040(HWND hDlg)
{
  void *v1; // ST08_4
  signed int i; // [esp+Ch] [ebp-24h]
  signed int v4; // [esp+10h] [ebp-20h]
  CHAR String; // [esp+18h] [ebp-18h]
  int v6; // [esp+19h] [ebp-17h]
  int v7; // [esp+1Dh] [ebp-13h]
  int v8; // [esp+21h] [ebp-Fh]
  int v9; // [esp+25h] [ebp-Bh]
  __int16 v10; // [esp+29h] [ebp-7h]
  char v11; // [esp+2Bh] [ebp-5h]

  strcpy(Text, "try again!");                   // //看到了,我们验证失败时候的字串
  strcpy(Caption, "fail");
  String = 0;
  v6 = 0;
  v7 = 0;
  v8 = 0;
  v9 = 0;
  v10 = 0;
  v11 = 0;
  GetDlgItemTextA(hDlg, 1001, &String, 20);
  v4 = 0;
  for ( i = 0; i < 20; ++i )
    v4 += *(&String + i);
  if ( v4 > 0 && v4 < 4132 )
  {
    v1 = malloc(v4);
    sub_401020();
    j___free_base(v1);
  }
  return MessageBoxA(0, Text, Caption, 0);
}
然而sub_401020()函数又是一个空函数,带着这个问题,我们继续分析TLS后面的内容。

  2.分析sub_401C10()函数

int sub_401C10()
{
  void *v0; // edx
  signed int j; // [esp+0h] [ebp-Ch]
  signed int i; // [esp+8h] [ebp-4h]

  sub_4018D0();
  lpAddress = v0;
  sub_4019B0(v0);
  for ( i = 0; i < 5; ++i )
    byte_4147DC[i] = *((_BYTE *)lpAddress + i + 32);
  *(_DWORD *)&byte_414028[1] = (char *)sub_401A10 - (char *)((_BYTE *)lpAddress + 32) - 5;
  for ( j = 0; j < 5; ++j )
    *((_BYTE *)lpAddress + j + 32) = byte_414028[j];
  return sub_4019E0(lpAddress);
}
这个函数看着和上一个函数很像,关键是v0(edx)指向的是什么地址呢?v0中的值看上去应该是  sub_4018D0()初始化的。先来看看这个函数。
分析这个函数之前我们先来温习点功课:FS段寄存器,TEB结构,PEB结构
      1)FS段寄存器指向当前的TEB结构,在TEB编译0x30处是PEB指针,通过这个指针即可获得PED的地址。
      2) TEB和PEB的结构如下:
typedef struct _NT_TIB
{                                           // Size: 01C
    struct _EXCEPTION_REGISTRATION_RECORD *ExceptionList; // 000
    PVOID StackBase;                        // 004
    PVOID StackLimit;                       // 008
    PVOID SubSystemTib;                     // 00C
    union                                   // 010
    {
        PVOID FiberData;
        ULONG Version;
    };
    PVOID ArbitraryUserPointer;             // 014
    struct _NT_TIB *Self;                   // 018
} NT_TIB, *PNT_TIB;
 
typedef struct _TEB 
{                                           // Size:  FBC
    NT_TIB Tib;                             // 000
    PVOID EnvironmentPointer;               // 01C
    CLIENT_ID Cid;                          // 020
    PVOID ActiveRpcHandle;                  // 028
    PVOID ThreadLocalStoragePointer;        // 02C
    struct _PEB *ProcessEnvironmentBlock;   // 030
    ULONG LastErrorValue;                   // 034
    ULONG CountOfOwnedCriticalSections;     // 038
    PVOID CsrClientThread;                  // 03C
    struct _W32THREAD* Win32ThreadInfo;     // 040
    ULONG User32Reserved[0x1A];             // 044
    ULONG UserReserved[5];                  // 0AC
    PVOID WOW32Reserved;                    // 0C0
    LCID CurrentLocale;                     // 0C4
    ULONG FpSoftwareStatusRegister;         // 0C8
    PVOID SystemReserved1[0x36];            // 0CC
    LONG ExceptionCode;                     // 1A4
    struct _ACTIVATION_CONTEXT_STACK *ActivationContextStackPointer; // 1A8
    UCHAR SpareBytes1[0x28];                // 1AC    
    GDI_TEB_BATCH GdiTebBatch;              // 1D4    
    CLIENT_ID RealClientId;                 // 6B4    
    PVOID GdiCachedProcessHandle;           // 6BC    
    ULONG GdiClientPID;                     // 6C0
    ULONG GdiClientTID;                     // 6C4    
    PVOID GdiThreadLocalInfo;               // 6C8    
    ULONG Win32ClientInfo[62];              // 6CC    
    PVOID glDispatchTable[0xE9];            // 7C4    
    ULONG glReserved1[0x1D];                // B68    
    PVOID glReserved2;                      // BDC    
    PVOID glSectionInfo;                    // BE0    
    PVOID glSection;                        // BE4    
    PVOID glTable;                          // BE8    
    PVOID glCurrentRC;                      // BEC    
    PVOID glContext;                        // BF0    
    NTSTATUS LastStatusValue;               // BF4    
    UNICODE_STRING StaticUnicodeString;     // BF8    
    WCHAR StaticUnicodeBuffer[0x105];       // C00    
    PVOID DeallocationStack;                // E0C    
    PVOID TlsSlots[0x40];                   // E10    
    LIST_ENTRY TlsLinks;                    // F10    
    PVOID Vdm;                              // F18    
    PVOID ReservedForNtRpc;                 // F1C    
    PVOID DbgSsReserved[0x2];               // F20    
    ULONG HardErrorDisabled;                // F28    
    PVOID Instrumentation[14];              // F2C    
    PVOID SubProcessTag;                    // F64    
    PVOID EtwTraceData;                     // F68    
    PVOID WinSockData;                      // F6C    
    ULONG GdiBatchCount;                    // F70    
    BOOLEAN InDbgPrint;                     // F74    
    BOOLEAN FreeStackOnTermination;         // F75    
    BOOLEAN HasFiberData;                   // F76    
    UCHAR IdealProcessor;                   // F77    
    ULONG GuaranteedStackBytes;             // F78    
    PVOID ReservedForPerf;                  // F7C    
    PVOID ReservedForOle;                   // F80    
    ULONG WaitingOnLoaderLock;              // F84    
    ULONG SparePointer1;                    // F88    
    ULONG SoftPatchPtr1;                    // F8C    
    ULONG SoftPatchPtr2;                    // F90    
    PVOID *TlsExpansionSlots;               // F94    
    ULONG ImpersionationLocale;             // F98    
    ULONG IsImpersonating;                  // F9C    
    PVOID NlsCache;                         // FA0    
    PVOID pShimData;                        // FA4    
    ULONG HeapVirualAffinity;               // FA8    
    PVOID CurrentTransactionHandle;         // FAC
    PTEB_ACTIVE_FRAME ActiveFrame;          // FB0    
    PVOID FlsData;                          // FB4    
    UCHAR SafeThunkCall;                    // FB8    
    UCHAR BooleanSpare[3];                  // FB9
} TEB, *PTEB; 
 
typedef struct _LIST_ENTRY
{                                           // Size: 008
    struct _LIST_ENTRY *Flink;              // 000 从前到后
    struct _LIST_ENTRY *Blink;              // 004 从后到前
} LIST_ENTRY, *PLIST_ENTRY;
 
typedef struct _PER_LDR_DATA
{                                           // Size: 0024
    ULONG Length;                           // 000
    BOOLEAN Initialize;                     // 004
    PVOID SsHandle;                         // 008
    LIST_ENTRY InLoadOrderModuleList;       // 00C
    LIST_ENTRY InMemoryOrderModuleList;     // 014
    LIST_ENTRY InInitializationOrderModuleList; // 01C
} PER_LDR_DATA, *PPER_LDR_DATA;
 
typedef struct _UNICODE_STRING 
{                                           // Size: 008
  USHORT  Length;                           // 000 占用的内存字节数,个数*2;
  USHORT  MaximumLength;                    // 002
  PWSTR  Buffer;                            // 004
} UNICODE_STRING ,*PUNICODE_STRING;
 
typedef struct _LDR_DATA_TABLE_ENTRY
{                                           // Size: 050
     LIST_ENTRY InLoadOrderLinks;           // 000 LIST_ENTRY里的Flink和Blink其实是指向LDR_MODULE结构,即LDR_DATA_TABLE_ENTRY
     LIST_ENTRY InMemoryOrderLinks;         // 008 同上
     LIST_ENTRY InInitializationOrderLinks; // 010 同上
     PVOID DllBase;                         // 018
     PVOID EntryPoint;                      // 01C
     ULONG SizeOfImage;                     // 020
     UNICODE_STRING FullDllName;            // 024
     UNICODE_STRING BaseDllName;            // 02C
     ULONG Flags;                           // 034
     WORD LoadCount;                        // 038
     WORD TlsIndex;                         // 03A
     union                                  // 03C
     {
          LIST_ENTRY HashLinks;             // 03C
          struct
          {
               PVOID SectionPointer;        // 03C
               ULONG CheckSum;              // 040
          };
     };
     union
     {
          ULONG TimeDateStamp;              // 044
          PVOID LoadedImports;              // 044
     };
     _ACTIVATION_CONTEXT * EntryPointActivationContext; // 048
     PVOID PatchInformation;                // 04C
} LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY;
 
typedef struct _PEB  
{                                           // Size: 1D8   
    UCHAR InheritedAddressSpace;            // 000  
    UCHAR ReadImageFileExecOptions;         // 001  
    UCHAR BeingDebugged;                    // 002   
    UCHAR SpareBool;                        // 003 Allocation size  
    HANDLE Mutant;                          // 004   
    HINSTANCE ImageBaseAddress;             // 008 
    struct _PER_LDR_DATA *Ldr;              // 00C
    strcut _RTL_USER_PPROCESS_PARAMETERS *ProcessParameters; // 010  
    ULONG SubSystemData;                    // 014  
    HANDLE DefaultHeap;                     // 018  
    KSPIN_LOCK FastPebLock;                 // 01C  
    ULONG FastPebLockRoutine;               // 020  
    ULONG FastPebUnlockRoutine;             // 024  
    ULONG EnvironmentUpdateCount;           // 028  
    ULONG KernelCallbackTable;              // 02C  
    LARGE_INTEGER SystemReserved;           // 030  
    struct _PER_FREE_BLOCK *FreeList;       // 038
    ULONG TlsExpansionCounter;              // 03C  
    ULONG TlsBitmap;                        // 040  
    LARGE_INTEGER TlsBitmapBits;            // 044  
    ULONG ReadOnlySharedMemoryBase;         // 04C  
    ULONG ReadOnlySharedMemoryHeap;         // 050  
    ULONG ReadOnlyStaticServerData;         // 054 
    ULONG AnsiCodePageData;                 // 058  
    ULONG OemCodePageData;                  // 05C  
    ULONG UnicodeCaseTableData;             // 060  
    ULONG NumberOfProcessors;               // 064   
    LARGE_INTEGER NtGlobalFlag;             // 068 Address of a local copy  
    LARGE_INTEGER CriticalSectionTimeout;   // 070  
    ULONG HeapSegmentReserve;               // 078  
    ULONG HeapSegmentCommit;                // 07C  
    ULONG HeapDeCommitTotalFreeThreshold;   // 080  
    ULONG HeapDeCommitFreeBlockThreshold;   // 084  
    ULONG NumberOfHeaps;                    // 088  
    ULONG MaximumNumberOfHeaps;             // 08C  
    ULONG ProcessHeaps;                     // 090  
    ULONG GdiSharedHandleTable;             // 094  
    ULONG ProcessStarterHelper;             // 098  
    ULONG GdiDCAttributeList;               // 09C  
    KSPIN_LOCK LoaderLock;                  // 0A0  
    ULONG OSMajorVersion;                   // 0A4  
    ULONG OSMinorVersion;                   // 0A8  
    USHORT OSBuildNumber;                   // 0AC  
    USHORT OSCSDVersion;                    // 0AE  
    ULONG OSPlatformId;                     // 0B0  
    ULONG ImageSubsystem;                   // 0B4  
    ULONG ImageSubsystemMajorVersion;       // 0B8  
    ULONG ImageSubsystemMinorVersion;       // 0BC  
    ULONG ImageProcessAffinityMask;         // 0C0  
    ULONG GdiHandleBuffer[0x22];            // 0C4  
    ULONG PostProcessInitRoutine;           // 14C  
    ULONG TlsExpansionBitmap;               // 150  
    UCHAR TlsExpansionBitmapBits[0x80];     // 154  
    ULONG SessionId;                        // 1D4    
} PEB, *PPEB;
好了有了TEB,PEB数据结构的支撑,我们来分析 sub_4018D0()函数
int sub_4018D0()
{
  int v0; // edx

  sub_4018F5(0x3BD696F4);
  return sub_401928(v0, 0x925DF53F);
}
0x3BD696F4是目标字串hash值,继续分析 sub_4018F5()
int __stdcall sub_4018F5(int hash)
{
  int hash_1; // ecx
  _DWORD *v2; // esi
  int hash_2; // ST08_4
  int v4; // ST04_4
  int len; // eax
  int result; // eax
  int v7; // edx

  hash_1 = hash;
  v2 = *(_DWORD **)(*(_DWORD *)(__readfsdword(0x30u) + 0xC) + 0x1C);// v2 = LIST_ENTRY InInitializationOrderModuleList;
  do
  {
    v2 = (_DWORD *)*v2;
    hash_2 = hash_1;
    v4 = v2[6];                                 // 获取FullDllName;
    len = strlen(v2[6]);                        // 计算字符串长度
    result = getHash(v4, 2 * len);              // 计算hash
    hash_1 = hash_2;
  }
  while ( result != hash_2 );
  v7 = v2[2];                                   // 获得指定dll基址(DllBase)
  return result;
0x30处是PEB的指针  :struct _PEB *ProcessEnvironmentBlock;// 030
PEB+0xc处的指针      :struct _PER_LDR_DATA *Ldr;// 00C
Ldr +0x1c处的指针     :LIST_ENTRY InInitializationOrderModuleList;
目标动态库:C:\Windows\syswow64\USER32.dll 基址存储在edx中
可以看到sub_4018F5(int hash)是根据指定hash获得动态库基址。将DLL基址和目标函数hash传入sub_401928()函数, 继续分析
int __stdcall sub_401928(int dllbase, int funcHash)
{
  _DWORD *v2; // esi
  int i; // eax
  int v4; // esi
  int v5; // eax
  int v7; // [esp-8h] [ebp-14h]
  int v8; // [esp+0h] [ebp-Ch]
  int v9; // [esp+4h] [ebp-8h]
  int v10; // [esp+8h] [ebp-4h]

  v2 = (_DWORD *)(dllbase + *(_DWORD *)(dllbase + *(_DWORD *)(dllbase + 0x3C) + 0x78));
  v10 = v2[7];
  v9 = v2[8];
  v8 = v2[9];
  for ( i = 0; ; i = v7 + 1 )
  {
    v4 = dllbase + *(_DWORD *)(dllbase + v9 + 4 * i);
    v7 = i;
    v5 = sub_401870(dllbase + *(_DWORD *)(dllbase + v9 + 4 * i));
    if ( getHash(v4, v5) == funcHash )
      break;
  }
  return dllbase + *(_DWORD *)(dllbase + v10 + 4 * *(unsigned __int16 *)(dllbase + v8 + 2 * v7));
}

该函数返回目标函数地址,目标函数为:GetDlgItemTextA()
这样找到了lpAddress指向的地址 GetDlgItemTextA()。我们看一下sub_401c10()函数修改后 GetDlgItemTextA()的情况
                    user32_GetDlgItemTextA proc near
user32.dll:76326BCE
user32.dll:76326BCE                arg_0= dword ptr  8
user32.dll:76326BCE                arg_4= dword ptr  0Ch
user32.dll:76326BCE                arg_8= dword ptr  10h
user32.dll:76326BCE                arg_C= dword ptr  14h
user32.dll:76326BCE
user32.dll:76326BCE 8B FF          mov     edi, edi
user32.dll:76326BD0 55             push    ebp
user32.dll:76326BD1 8B EC          mov     ebp, esp
user32.dll:76326BD3 FF 75 0C       push    [ebp+arg_4]
user32.dll:76326BD6 FF 75 08       push    [ebp+arg_0]
user32.dll:76326BD9 E8 7C CB FA FF call    near ptr user32_GetDlgItem
user32.dll:76326BDE 85 C0          test    eax, eax
user32.dll:76326BE0 74 0E          jz      short near ptr loc_76326BEE+2
user32.dll:76326BE2 FF 75 14       push    [ebp+arg_C]
user32.dll:76326BE5 FF 75 10       push    [ebp+arg_8]
user32.dll:76326BE8 50             push    eax
user32.dll:76326BE9 E8 53 94 FA FF call    near ptr user32_GetWindowTextA
user32.dll:76326BEE
user32.dll:76326BEE                loc_76326BEE:                           ; CODE XREF: user32_GetDlgItemTextA+12↑j
user32.dll:76326BEE E9 1D AE CE 89 jmp     sub_11A10
在执行 GetDlgItemTextA()后会jmp 到sub_11A10()执行。我们翻回头在看 DialogFunc ,TLS并没有对sub_401020()做什么,而是在 GetDlgItemTextA()函数尾hook了该函数,转而执行 sub_11A10()。
int __usercall sub_401A10@<eax>(int a1@<ecx>, int a2@<ebp>, int a3@<esi>)
{
  unsigned int v3; // et0
  int v4; // eax
  _BYTE *v5; // ecx
  unsigned int v7; // [esp-24h] [ebp-24h]
  int v8; // [esp-18h] [ebp-18h]

  v8 = a1;
  v3 = __readeflags();
  v7 = v3;
  dword_414800 = a3;
  dword_4147EC = *(_DWORD *)(a2 + 20);
  dword_4147F0 = malloc(dword_4147EC);
  dword_4147F4 = a2 + 16;
  memmove(dword_4147F0, *(const void **)(a2 + 16), dword_4147EC);
  *(_DWORD *)(a2 - 16) = dword_4147F0;
  *(_DWORD *)(a2 - 20) = *(_DWORD *)(a2 - 16) + 1;
  do
    *(_BYTE *)(a2 - 21) = *(_BYTE *)(*(_DWORD *)(a2 - 16))++;
  while ( *(_BYTE *)(a2 - 21) );
  *(_DWORD *)(a2 - 28) = *(_DWORD *)(a2 - 16) - *(_DWORD *)(a2 - 20);
  if ( (unsigned __int8)sub_401290((int)dword_4147F0, *(_DWORD *)(a2 - 28)) )
  {
    v4 = sub_401870((int)dword_4147F0);
    if ( getHash((int)dword_4147F0, v4) == 1446302290 )
    {
      v5 = off_414030;
      *(_WORD *)off_414030 = 0;
      v5[2] = 0;
      for ( *(_WORD *)(a2 - 4) = 0; *(signed __int16 *)(a2 - 4) < 8; ++*(_WORD *)(a2 - 4) )
        *((char *)off_414030 - *(signed __int16 *)(a2 - 4)) = (39 - *(unsigned __int16 *)(a2 - 4)) ^ byte_41401C[7 - *(signed __int16 *)(a2 - 4)];
      *(_WORD *)off_414034 = 0;
      for ( *(_WORD *)(a2 - 8) = 0; *(signed __int16 *)(a2 - 8) < 3; ++*(_WORD *)(a2 - 8) )
        *((char *)off_414034 - *(signed __int16 *)(a2 - 8)) = (34 - *(unsigned __int16 *)(a2 - 8)) ^ byte_414024[2 - *(signed __int16 *)(a2 - 8)];
    }
  }
  j___free_base(dword_4147F0);
  dword_4147F8 = (int (__thiscall *)(_DWORD))((char *)lpAddress + 32);
  sub_4019B0(lpAddress);
  for ( *(_DWORD *)(a2 - 12) = 0; *(_DWORD *)(a2 - 12) < 5; ++*(_DWORD *)(a2 - 12) )
    *((_BYTE *)lpAddress + *(_DWORD *)(a2 - 12) + 32) = byte_4147DC[*(_DWORD *)(a2 - 12)];
  sub_4019E0(lpAddress);
  dword_4147FC = 1;
  __writeeflags(v7);
  return dword_4147F8(v8);
}
到此TLS函数分析完成。

     函数 401A10 为真正的check函数,其调用 sub_401290函数,如果 sub_401290函数返回1,则起再次计算输入sn的hash值,并判断此hash值是否等于0x5634D252,如果相等,则将全局字串改为; "try again!"改为success'" ,"fail"改为 "ok"。

3、判定程序

程序的主要判断逻辑在sub_401290()中
bool __cdecl sub_401290(char *sn, int len)
{
  byte_4147D0[0] = 4;
  byte_4147D0[1] = 1;
  byte_4147D0[2] = 3;
  byte_4147D0[3] = 7;
  byte_4147D0[4] = 2;
  byte_4147D0[5] = 5;
  byte_4147D0[6] = 8;
  byte_4147D0[7] = 6;
  byte_4147D0[8] = 0;
  return sub_4015B0(sn, len);
}

bool __cdecl sub_4015B0(char *sn, int len)
{
  int i; // [esp+0h] [ebp-Ch]
  signed int v4; // [esp+8h] [ebp-4h]

  v4 = 0xCCCCCCCC;
  if ( len % 2 )
    return 0;
  for ( i = 0; i < len; i += 2 )
  {
    if ( sn[i] == 'w' )
      v4 = 0;
    if ( sn[i] == 'd' )
      v4 = 1;
    if ( sn[i] == 's' )
      v4 = 2;
    if ( sn[i] == 'a' )
      v4 = 3;
    if ( !(unsigned __int8)sub_401380(v4, sn[i + 1] - 48) )
      return 0;
  }
  return byte_4147D0[0] == 1
      && byte_4147D0[1] == 2
      && byte_4147D0[2] == 3
      && byte_4147D0[3] == 4
      && byte_4147D0[4] == 5
      && byte_4147D0[5] == 6
      && byte_4147D0[6] == 7
      && byte_4147D0[7] == 8
      && !byte_4147D0[8];
}
char __cdecl sub_401380(int a1, int a2)
{
  char result; // al
  signed int i; // [esp+8h] [ebp-8h]
  signed int v4; // [esp+Ch] [ebp-4h]

  if ( !a2 )
    return 0;
  v4 = 0;
LABEL_4:
  if ( v4 >= 3 )
    return 0;
  for ( i = 0; ; ++i )
  {
    if ( i >= 3 )
    {
      ++v4;
      goto LABEL_4;
    }
    if ( byte_4147D0[3 * v4 + i] == a2 )
      break;
LABEL_6:
    ;
  }
  switch ( a1 )
  {
    case 0:
      if ( v4 )
      {
        if ( byte_4147D0[3 * (v4 - 1) + i] )
        {
          result = 0;
        }
        else
        {
          byte_4147D0[3 * (v4 - 1) + i] = byte_4147D0[3 * v4 + i];
          byte_4147D0[3 * v4 + i] = 0;
          result = 1;
        }
      }
      else
      {
        result = 0;
      }
      break;
    case 1:
      if ( i == 2 )
      {
        result = 0;
      }
      else if ( byte_4147D1[3 * v4 + i] )
      {
        result = 0;
      }
      else
      {
        byte_4147D1[3 * v4 + i] = byte_4147D0[3 * v4 + i];
        byte_4147D0[3 * v4 + i] = 0;
        result = 1;
      }
      break;
    case 2:
      if ( v4 == 2 )
      {
        result = 0;
      }
      else if ( byte_4147D0[3 * (v4 + 1) + i] )
      {
        result = 0;
      }
      else
      {
        byte_4147D0[3 * (v4 + 1) + i] = byte_4147D0[3 * v4 + i];
        byte_4147D0[3 * v4 + i] = 0;
        result = 1;
      }
      break;
    case 3:
      if ( i )
      {
        if ( byte_4147CF[3 * v4 + i] )
        {
          result = 0;
        }
        else
        {
          byte_4147CF[3 * v4 + i] = byte_4147D0[3 * v4 + i];
          byte_4147D0[3 * v4 + i] = 0;
          result = 1;
        }
      }
      else
      {
        result = 0;
      }
      break;
    default:
      goto LABEL_6;
  }
  return result;
}
     sub_401290函数初始化为char 4147D0[9] = {4,1,3,7,2,5,8,6,0}; 调用sub_4015B0函数根据输入sn对 4147D0[9]内容进行调整(加密)后,如果 char 4147D0[9]值变为 {1,2,3,4,5,6,7,8,0},则成功。算法类似一个简单的华容道,路线如下图:


flag:d6d8s7s4a1w2a5w6

















[公告]安全服务和外包项目请将项目需求发到看雪企服平台:https://qifu.kanxue.com

最后于 2018-12-13 11:59 被ODPan编辑 ,原因:
最新回复 (7)
万剑归宗 1 2018-12-13 14:39
2
0
好有趣啊
yber 2018-12-13 22:03
3
0
有意思  一定得找个时间研究一番
yber 2018-12-13 22:03
4
0
有意思  一定得找个时间研究一番
yber 2018-12-13 22:04
5
0
有意思  一定得找个时间研究一番
yber 2018-12-13 22:04
6
0
有意思  一定得找个时间研究一番
yber 2018-12-13 22:05
7
0
有意思  一定得找个时间研究一番
aiening 2018-12-14 22:33
8
0
看懂最后那个算法,应该是一个怎样的循序渐进的过程呢?多去研究算法就可以吗?
游客
登录 | 注册 方可回帖
返回