首页 > 其他分享 >MobaXterm24.2 分析

MobaXterm24.2 分析

时间:2024-09-22 20:34:11浏览次数:1  
标签:分析 __ MobaXterm24.2 TForm1 int result str BCEC40

MobaXterm

目录

MobaXterm_Personal_24.2.exe

delphi 程序 分析首选IDR,生成IDC脚本后结合 IDA PRO分析

注意:IDA 不能只看F5的反编译结果,如果未修正函数调用方式、栈参数时,结果往往不正确;需要看汇编确定参数。

0、启动窗口 TForm1

image-20240921120353791

1、TForm1_FormCreate

decrypt_9FDA48

当指定 “-chklic keyfilepath" 时,会验证文件keyfilepath

int __usercall decrypt_9FDA48@<eax>(char **a1@<ecx>, int key@<edx>, int a3@<eax>)
{
  // [COLLAPSED LOCAL DECLARATIONS. PRESS KEYPAD CTRL-"+" TO EXPAND]

  a3a = 0;
  v7 = &savedregs;
  v6[1] = (unsigned int)&loc_9FDA90;
  v6[0] = (unsigned int)NtCurrentTeb()->NtTib.ExceptionList;
  __writefsdword(0, (unsigned int)v6);
  xxBase64Decode_9FD940(a3, (int)a1, (unsigned int)&a3a);
  DecryptBytes_9FD9DC((char *)a3a, key, a1);
  __writefsdword(0, v6[0]);
  v7 = (int *)&loc_9FDA97;
  return LStrClr();
}

1)xxBase64Decode_9FD80C

相较标准base64,字节序解析不同

int __usercall xxBase64Decode_9FD80C@<eax>(unsigned __int8 *a1@<eax>, int *a2@<edx>)
{
  // [COLLAPSED LOCAL DECLARATIONS. PRESS KEYPAD CTRL-"+" TO EXPAND]

  // 相较标准base64,字节序解析不同
  v4 = LStrLen((int)a1) - 2;
  if ( v4 )
  {
    v6 = v4 - 1;
    if ( v6 )
    {
      result = v6 - 1;
      if ( !result )
      {
        LStrSetLength(
          a2,
          3,
          v5,
          ((unsigned __int8)index_table_BA26F4[a1[3]] << 0x12)
        + ((unsigned __int8)index_table_BA26F4[a1[2]] << 0xC)
        + ((unsigned __int8)index_table_BA26F4[a1[1]] << 6)
        + (unsigned __int8)index_table_BA26F4[*a1]);
        v12 = LStrLen(*a2);
        v13 = UniqueStringA(v12);
        return Move(v16, v13);
      }
    }
    else
    {
      LStrSetLength(
        a2,
        2,
        v5,
        ((unsigned __int8)index_table_BA26F4[a1[2]] << 0xC)
      + ((unsigned __int8)index_table_BA26F4[a1[1]] << 6)
      + (unsigned __int8)index_table_BA26F4[*a1]);
      v10 = LStrLen(*a2);
      v11 = UniqueStringA(v10);
      return Move(v15, v11);
    }
  }
  else
  {
    LStrSetLength(
      a2,
      1,
      v5,
      ((unsigned __int8)index_table_BA26F4[a1[1]] << 6) + (unsigned __int8)index_table_BA26F4[*a1]);
    v8 = LStrLen(*a2);
    v9 = UniqueStringA(v8);
    return Move(v14, v9);
  }
  return result;
}


2)DecryptBytes_9FD9DC

字节xor

int __usercall DecryptBytes_9FD9DC@<eax>(char *a1@<eax>, int reuse_key_or_index@<edx>, char **d_str@<ecx>)
{
  __int16 key; // si
  int result; // eax
  char *v7; // [esp+0h] [ebp-18h]
  __int16 v8; // [esp+4h] [ebp-14h]

  v7 = a1;
  LStrAsg((volatile __int32 *)d_str, (__int32)a1);
  key = reuse_key_or_index;
  result = LStrLen((int)*d_str);
  if ( !(_WORD)result )
    return result;
  v8 = result;
  LOWORD(reuse_key_or_index) = 1;
  do
  {
    *(_BYTE *)(UniqueStringA(v7) + (unsigned __int16)reuse_key_or_index - 1) = HIBYTE(key) ^ (*d_str)[(unsigned __int16)reuse_key_or_index - 1];
    result = (unsigned __int8)v7[(unsigned __int16)reuse_key_or_index - 1];
    key = result & key | 0x482D;
    ++reuse_key_or_index;
    --v8;
  }
  while ( v8 );
  return result;
}

2、许可结构

经过解密后,许可信息使用‘#’分隔为7部分

    lic_format='{0}#{1}#{2}#{3}#{4}#{5}#{6}#'.format(
        Type,
        '{}|{}{}'.format(UserName, MajorVersion, MinorVersion),
        Count,# number
        '{}3{}6{}'.format(MajorVersion,MinorVersion,MinorVersion),
        number,#unuse
        NoGames,
        NoPlugins,
    )

1) Type

结合TFormAbout_FormCreate 分析得到

Professional Edition    1
unknow? trial version   2
Educational Edition		3
Personal Edition		4

2) version_info_3A8

'{}|{}{}'.format(UserName, MajorVersion, MinorVersion),

  LStrLAsg(&version, "24.2.0.5220");
  LStrAsg(&v671->ver_3_46_F84, (__int32)"3.46");
  LStrAsg(&v671->ver_3_02_F88, (__int32)"2.02");
  str_find_AA7528(version, 1, '.', &v638);      // 24
  v427 = v638;
  v426 = ".";
  str_find_AA7528(version, 2, '.', &v637);      // 2
  v424 = v637;
  // LStrCatN
  // eax,edx  (栈不定参数,从左到右入栈)
  LStrCatN((char **)&v671->version_info_3A8, 3);// 24.2
                                                // 这里ida 没有识别对不定参数(因为前面有些函数没有调整,导致这里没能给出不定参数)

3) user_limit

在TForm1_FormCreate 和TFormAbout_FormCreate引用

4) Version

'{}3{}6{}'.format(MajorVersion,MinorVersion,MinorVersion),

5) unuse

未使用

6)NoGames

可在sub_A03F80 中看到相关应用

7)NoPlugins

可在sub_A03F80 中看到相关应用

解析函数parse_9FEB5C

int __usercall parse_9FEB5C@<eax>(__int32 a1@<eax>, __int32 a2@<ecx>)
{
  // [COLLAPSED LOCAL DECLARATIONS. PRESS KEYPAD CTRL-"+" TO EXPAND]

  _InterlockedExchange(&v60, a2);
  v60 = a1;
  LStrAddRef(v24, v25, v26);
  v23 = &savedregs;
  v22 = &loc_9FF193;
  ExceptionList = NtCurrentTeb()->NtTib.ExceptionList;
  __writefsdword(0, (unsigned int)&ExceptionList);
  LStrClr();
  v20[2] = &savedregs;
  v20[1] = &loc_9FF15E;
  v20[0] = NtCurrentTeb()->NtTib.ExceptionList;
  __writefsdword(0, (unsigned int)v20);
  Trim(v60, (int)&temp);
  v3 = 0x19;
  LOBYTE(v3) = gvar_009FF1A4;
  v19 = v3;
  v18 = &v51;
  StringReplace(temp, (int)"=", 0);
  LStrLAsg(&temp, v51);
  decrypt_9FDA48((char **)&v50, 0x787, temp);
  LStrLAsg(&temp, v50);
  if ( temp )
  {
    v17 = &savedregs;
    v16 = &loc_9FF0AF;
    v15 = NtCurrentTeb()->NtTib.ExceptionList;
    __writefsdword(0, (unsigned int)&v15);
    // license 使用'#' 分隔为7部分
    str_find_AA7528(temp, 1, '#', &v49);
    Trim(v49, (int)&type);                      // 第一部分:许可类型 1,3,4
    str_find_AA7528(temp, 2, '#', &v48);
    Trim(v48, (int)&lic_info);                  // UserName|MajorVersion.MinorVersion
    str_find_AA7528(temp, 3, '#', &v47);
    Trim(v47, (int)&count);                     // user_limit
    str_find_AA7528(temp, 4, '#', &v46);
    Trim(v46, (int)&iMinorVersion);             // {MajorVersion}3{MinorVersion}6{MinorVersion}
    str_find_AA7528(temp, 5, '#', &v45);
    Trim(v45, (int)unknow);                     // unuse
    str_find_AA7528(temp, 6, '#', &v44);
    Trim(v44, (int)&NoGames);
    str_find_AA7528(temp, 7, '#', &v43);
    Trim(v43, (int)&NoPlugins);
    v4 = StrToInt(type);
    // license 许可类型
    TForm1_BCEC40->license_type_F8C = v4;
    if ( !v4 )
      goto LABEL_21;
    license_type_F8C = TForm1_BCEC40->license_type_F8C;
    if ( license_type_F8C == 1 || license_type_F8C == 3 || license_type_F8C == 4 )
    {
      // 24.2
      str_find_AA7528(TForm1_BCEC40->version_info_3A8, 1, '.', &v41);// 24
      // push    offset a3_18    ; "3"
      str_find_AA7528(TForm1_BCEC40->version_info_3A8, 2, '.', &v40);// 2
      //   push    offset a6_19    ; "6"
      str_find_AA7528(TForm1_BCEC40->version_info_3A8, 2, '.', &v39);// 2
      LStrCatN(&v42, 5, v39);                   // 版本号,x.y  {MajorVersion}3{MinorVersion}6{MinorVersion}
                                                // {x}3{y}6{y}
                                                // 243262
      LStrCmp((int)iMinorVersion, (int *)v42);
      if ( v6 )                                 // zf
      {
        // -->相等时
        str_find_AA7528(lic_info, 2, '|', &v32);
        str_find_AA7528(TForm1_BCEC40->version_info_3A8, 1, '.', &v31);// 24
        str_find_AA7528(TForm1_BCEC40->version_info_3A8, 2, '.', &v30);// 2
        LStrCat(v11, v30);
        LStrCmp((int)&v31, (int *)v31);
        if ( v6 )                               // zf
        {
          // 相等时
          str_find_AA7528(lic_info, 1, '|', v29);
          StringReplace(v29[0], (int)"\\", 0);
          LStrAsg(&TForm1_BCEC40->username_F9C, v29[1]);
          utf8_dec_AB6800((char *)TForm1_BCEC40->username_F9C, &v28);
          LStrAsg(&TForm1_BCEC40->username_F9C, v28);
          StrToInt(count);
          IntToStr(v8, (int)&v27);
          LStrAsg(&TForm1_BCEC40->user_limit_FA0, v27);
          TForm1_BCEC40->NoGames_FA4 = 1;
          TForm1_BCEC40->NoPlugins_FA5 = 1;
          LStrCmp(NoGames, (int *)"1");
          if ( !v6 )
            TForm1_BCEC40->NoGames_FA4 = 0;
          LStrCmp(NoPlugins, (int *)"1");
          if ( !v6 )
            TForm1_BCEC40->NoPlugins_FA5 = 0;
        }
        else
        {
          TForm1_BCEC40->license_type_F8C = 0;
        }
      }
      else
      {
        TForm1_BCEC40->license_type_F8C = 0;
        if ( (unsigned __int8)*iMinorVersion >= '1'
          && (unsigned __int8)*iMinorVersion <= *(_BYTE *)TForm1_BCEC40->version_info_3A8
          && (unsigned __int8)iMinorVersion[1] >= '0'
          && (unsigned __int8)iMinorVersion[1] <= '9'
          && (unsigned __int8)iMinorVersion[3] >= '0'
          && (unsigned __int8)iMinorVersion[3] <= '9' )
        {
          v38[1] = *iMinorVersion;
          v38[0] = 1;
          PStrCpy((int)v37, (unsigned __int8 *)v38);
          v36 = iMinorVersion[1];
          d_str = 1;
          PStrNCat(v37, (unsigned __int8)&d_str, 2u);
          PStrCpy((int)v34, (unsigned __int8 *)v37);
          PStrNCat(v34, (unsigned __int8)"\x01.", 3u);
          PStrCpy((int)v33, (unsigned __int8 *)v34);
          v36 = iMinorVersion[3];
          d_str = 1;
          PStrNCat(v33, (unsigned __int8)&d_str, 4u);
          LStrFromString(v7, (unsigned __int8 *)v33);
        }
      }
      goto LABEL_22;
    }
    if ( license_type_F8C == 2 )                // unknow
    {
LABEL_21:
      TForm1_BCEC40->dwordF90 = StrToInt(lic_info);
      TForm1_BCEC40->dwordF94 = StrToInt(count);
      TForm1_BCEC40->dwordF98 = StrToInt((int)iMinorVersion);
    }
LABEL_22:
    __writefsdword(0, v12);
  }
  v9 = TForm1_BCEC40->license_type_F8C;
  if ( (v9 == 1 || v9 == 3 || v9 == 4) && (!TForm1_BCEC40->username_F9C || !TForm1_BCEC40->user_limit_FA0) )
    TForm1_BCEC40->license_type_F8C = 0;
  __writefsdword(0, v13);
  __writefsdword(0, v14);
  LStrArrayClr(&loc_9FF19A);
  return LStrArrayClr(v16);
}

other

sub_A03F80

NoGames_FA4

NoPlugins_FA5

    TForm1_BCEC40->NoGames_FA4 = (*(int (__fastcall **)(const char *, const char *, int))(*(_DWORD *)TForm1_BCEC40->field_E08
                                                                                        + 0x10))(
                                   "NoGame",
                                   "Customization",
                                   1);
    v62 = 1;
    TForm1_BCEC40->NoPlugins_FA5 = (*(int (__fastcall **)(const char *, const char *, int))(*(_DWORD *)TForm1_BCEC40->field_E08
                                                                                          + 0x10))(
                                     "NoPingus",
                                     "Customization",
                                     1);

TFormAbout_FormCreate

about

  LStrCmp((*TForm1_ptr_00BA4964)->user_limit_FA0, (int *)"1");
  if ( v8 )
  {
    LStrLAsg(&v39, "(1 user)");
  }
  else
  {
    LStrCmp((*TForm1_ptr_00BA4964)->user_limit_FA0, (int *)"Unlimited");
    if ( v8 || (LStrCmp((*TForm1_ptr_00BA4964)->user_limit_FA0, (int *)"0"), v8) )
      LStrClr();
    else
      LStrCatN(&v39, 3, " users)", (*TForm1_ptr_00BA4964)->user_limit_FA0, "(");
  }
  license_type_F8C = (*TForm1_ptr_00BA4964)->license_type_F8C;
  if ( license_type_F8C == 1 || license_type_F8C == 3 || license_type_F8C == 4 )
  {
    if ( license_type_F8C == 1 )
    {
      v21 = "Professional Edition v";
      v20 = (void *)(*TForm1_ptr_00BA4964)->version_info_3A8;
      v19 = v38;
      IntToStr(v9, (int)&v33);
      LStrCatN(v34, 5, v33, " Build ");
      TControl_SetText(v11, (int *)v34[0]);
    }
    else if ( license_type_F8C == 3 )
    {
      v21 = "Educational Edition v";
      v20 = (void *)(*TForm1_ptr_00BA4964)->version_info_3A8;
      v19 = v38;
      IntToStr(v9, (int)&v31);
      LStrCatN(&v32, 5, v31, " Build ");
      TControl_SetText(v12, (int *)v32);
      LStrLAsg(&v39, "(for educational use only)");
    }
    else
    {
      v21 = "Personal Edition v";
      v20 = (void *)(*TForm1_ptr_00BA4964)->version_info_3A8;
      v19 = v38;
      IntToStr(v9, (int)&v29);
      LStrCatN(&v30, 5, v29, " Build ");
      TControl_SetText(v13, (int *)v30);
      LStrLAsg(&v39, "(for personal use only)");
    }
    LStrCatN(&v28, 4, v39, " ", (*TForm1_ptr_00BA4964)->username_F9C, "This version is registered to ");
    TControl_SetText(v14, (int *)v28);
    TControl_SetVisible(v40[0xC8], 0);
  }

py

keygen by Double Sine DoubleLabyrinth

#/usr/bin/env python3
'''
Author: Double Sine
License: GPLv3
'''
import random
from typing import Union
import os, sys, zipfile
# import base64

VariantBase64Table = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='
VariantBase64Dict = { i : VariantBase64Table[i] for i in range(len(VariantBase64Table)) }
VariantBase64ReverseDict = { VariantBase64Table[i] : i for i in range(len(VariantBase64Table)) }

def VariantBase64Encode(bs : bytes):
    result = b''
    blocks_count, left_bytes = divmod(len(bs), 3)

    for i in range(blocks_count):
        coding_int = int.from_bytes(bs[3 * i:3 * i + 3], 'little')
        block = VariantBase64Dict[coding_int & 0x3f]
        block += VariantBase64Dict[(coding_int >> 6) & 0x3f]
        block += VariantBase64Dict[(coding_int >> 12) & 0x3f]
        block += VariantBase64Dict[(coding_int >> 18) & 0x3f]
        result += block.encode()

    if left_bytes == 0:
        return result
    elif left_bytes == 1:
        coding_int = int.from_bytes(bs[3 * blocks_count:], 'little')
        block = VariantBase64Dict[coding_int & 0x3f]
        block += VariantBase64Dict[(coding_int >> 6) & 0x3f]
        result += block.encode()
        return result
    else:
        coding_int = int.from_bytes(bs[3 * blocks_count:], 'little')
        block = VariantBase64Dict[coding_int & 0x3f]
        block += VariantBase64Dict[(coding_int >> 6) & 0x3f]
        block += VariantBase64Dict[(coding_int >> 12) & 0x3f]
        result += block.encode()
        return result

def VariantBase64Decode(s : str):
    if isinstance(s,bytes):
        s=s.decode()
    result = b''
    blocks_count, left_bytes = divmod(len(s), 4)

    for i in range(blocks_count):
        block = VariantBase64ReverseDict[s[4 * i]]
        block += VariantBase64ReverseDict[s[4 * i + 1]] << 6
        block += VariantBase64ReverseDict[s[4 * i + 2]] << 12
        block += VariantBase64ReverseDict[s[4 * i + 3]] << 18
        result += block.to_bytes(3, 'little')

    if left_bytes == 0:
        return result
    elif left_bytes == 2:
        block = VariantBase64ReverseDict[s[4 * blocks_count]]
        block += VariantBase64ReverseDict[s[4 * blocks_count + 1]] << 6
        result += block.to_bytes(1, 'little')
        return result
    elif left_bytes == 3:
        block = VariantBase64ReverseDict[s[4 * blocks_count]]
        block += VariantBase64ReverseDict[s[4 * blocks_count + 1]] << 6
        block += VariantBase64ReverseDict[s[4 * blocks_count + 2]] << 12
        result += block.to_bytes(2, 'little')
        return result
    else:
        raise ValueError('Invalid encoding.')

def EncryptBytes(key : int, bs : bytes):
    result = bytearray()
    for i in range(len(bs)):
        result.append(bs[i] ^ ((key >> 8) & 0xff))
        key = result[-1] & key | 0x482D
    return bytes(result)

def DecryptBytes(key : int, bs : bytes):
    result = bytearray()
    for i in range(len(bs)):
        result.append(bs[i] ^ ((key >> 8) & 0xff))
        key = bs[i] & key | 0x482D
    return bytes(result)

class LicenseType:
    Professional = 1
    Educational = 3
    Persional = 4

def GenerateLicense(Type : LicenseType, Count :Union[int,str] , UserName : str, MajorVersion : int, MinorVersion,NoGames=0,NoPlugins=0):
    # 
    if isinstance(Count,str) :
        if Count.isdecimal():
            Count=int(Count)
    assert(Count >= 0) 
    # 'Unlimited'  or number
    '''

    LicenseString = '%d#%s|%d%d#%d#%d3%d6%d#%d#%d#%d#' % (Type, 
                                                          UserName, MajorVersion, MinorVersion, 
                                                          Count, 
                                                          MajorVersion, MinorVersion, MinorVersion,
                                                          0,    # Unknown
                                                          NoGames,    # No Games flag. 0 means "NoGames = false". But it does not work.
                                                          NoPlugins)    # No Plugins flag. 0 means "NoPlugins = false". But it does not work.
    '''
    x=0
    # x=random.randint(0,0xff)
    lic_format='{0}#{1}#{2}#{3}#{4}#{5}#{6}#'.format(
        Type,
        '{}|{}{}'.format(UserName, MajorVersion, MinorVersion),
        Count,# number or 'Unlimited'
        '{}3{}6{}'.format(MajorVersion,MinorVersion,MinorVersion),
        x,#unuse
        NoGames,
        NoPlugins,
    )
    LicenseString=lic_format
    EncodedLicenseString = VariantBase64Encode(EncryptBytes(0x787, LicenseString.encode())).decode()
    return EncodedLicenseString

def help():
    print('Usage:')
    print('    MobaXterm-Keygen.py <UserName> <Version>')
    print()
    print('    <UserName>:      The Name licensed to')
    print('    <Version>:       The Version of MobaXterm')
    print('                     Example:    24.2')
    print()


def main():
    if len(sys.argv) != 3:
        help()
        exit(0)
    else:
        MajorVersion, MinorVersion = sys.argv[2].split('.')[0:2]
        MajorVersion = int(MajorVersion)
        MinorVersion = int(MinorVersion)

        EncodedLicenseString=GenerateLicense(LicenseType.Professional, 
                        1,
                        sys.argv[1], #username
                        MajorVersion, 
                        MinorVersion)

        with zipfile.ZipFile('Custom.mxtpro', 'w') as f:
            f.writestr('Pro.key', data = EncodedLicenseString)
        print('[*] Success!')
        print('[*] File generated: %s' % os.path.join(os.getcwd(), 'Custom.mxtpro'))
        print('[*] Please move or copy the newly-generated file to MobaXterm\'s installation path.')
        print()
# else:
#     print('[*] ERROR: Please run this script directly')    





    
def test():
    EncodedLicenseString=GenerateLicense(LicenseType.Professional, 
                        1,
                        'test', 
                        24, 
                        2)    
    print('EncodedLicenseString:',EncodedLicenseString)
    with open('temp.key','w') as f:
          f.write(EncodedLicenseString)
    print('''cmd:\n
          MobaXterm_Personal_24.2.exe -chklic temp.key
          ## will auto generate 'Custom.mxtpro'
          ''')

if __name__ == '__main__':
    #main()

    test()

image-20240922201622421

标签:分析,__,MobaXterm24.2,TForm1,int,result,str,BCEC40
From: https://www.cnblogs.com/DirWang/p/18425825

相关文章

  • 关于订单信息的Excel数据分析报告
    提升自己,掌握数据分析的能力,最快的方式就是实践! 这里又是一个Excel数据分析项目的分析报告,有需要项目配套数据集的可以关注私信我免费获取(●'◡'●)     ......
  • 【笔记】材料分析测试:晶体学
    晶体与晶体结构CrystalandCrystalStructure1.晶体主要特征固态物质可以分为晶态和非晶态两大类,分别称为晶体和非晶体。晶体和非晶体在微观结构上的区别在于是否具有长程有序。晶体(长程有序)非晶(短程有序)准晶:介于晶体和非晶体之间。准晶体具有与晶体相似的长程有序的......
  • 深度剖析智能养老设备市场分析:现状、趋势与前景
    本文深入探讨了智能养老设备市场的现状、趋势与前景。通过对市场的全面分析,揭示了当前智能养老设备市场所面临的问题以及未来的发展机遇。同时,合理分布了相关关键词,为读者提供了有价值且信息丰富的内容。一、引言人口老龄化的加剧,智能养老设备市场逐渐成为关注的焦点。智能养老......
  • 客户转化预测以及关键因素识别_支持向量机与相关性分析
    数据入口:数字营销转化数据集-Heywhale.com数据集记录了客户与数字营销活动的互动情况。它涵盖了人口统计数据、营销特定指标、客户参与度指标以及历史购买数据,为数字营销领域的预测建模和分析提供了丰富的信息。数据说明:字段说明CustomerID每个客户的唯一标识符。Age客户......
  • 【计算机毕设-大数据方向】基于大数据的在线车辆数据分析可视化系统的设计与实现
    ......
  • Android轻量级RTSP服务使用场景分析和设计探讨
    技术背景好多开发者,对我们Android平台轻量级RTSP服务模块有些陌生,不知道这个模块具体适用于怎样的场景,有什么优缺点,实际上,我们的Android平台轻量级RTSP服务模块更适用于内网环境下、对并发要求不高的场景,实现低成本、低延迟的音视频实时传输。本文就上述问题,做个技术探讨,先说......
  • 帆软杯——中国云游戏行业研究分析
    帆软杯中国云游戏行业研究分析1.团队介绍2.作品背景3.制作流程3.1数据来源3.2整体架构与思路4.成果展示4.1中国云游戏行业发展现状4.2中国云游戏用户特征分析4.3中国云游戏产业链分析4.4中国云游戏面临新挑战4.5中国云游戏未来展望5.获奖证书中国云游戏......
  • [数据结构与算法·C++] 笔记 1.4 算法复杂性分析
    1.4算法复杂性分析算法的渐进分析数据规模n逐步增大时,f(n)的增长趋势当n增大到一定值以后,计算公式中影响最大的就是n的幂次最高的项其他的常数项和低幂次项都可以忽略大O表示法函数f,g定义域为自然数,值域非负实数集定义:如果存在正数c和n,使得对任意的......
  • Flink数据源拆解分析(WikipediaEditsSource)
    在demo中,WikipediaEditsSource类作为数据源负责向Flink提供实时消息,今天咱们一起来分析其源码,了解Flink是怎么获取到来自Wiki的实时数据的,这对我们今后做自定义数据源也有很好的参考作用;官方解释以下是官网对消息来源的说明,维基百科提供了一个IRC协议的通道,从这个通道可以获取对......
  • 【计算机毕设-大数据方向】基于Hadoop的新闻资讯数据分析可视化系统的设计与实现
    ......