当前位置: 首页 > news >正文

MFC逆向之CrackMe Level3 过反调试 + 写注册机

今天我来分享一下,过反调试的方法以及使用IDA还原代码 + 写注册机的过程

由于内容太多,我准备分为两个帖子写,这个帖子主要是写IDA还原代码,下一个帖子是写反调试的分析以及过反调试和异常

这个CrackMe Level3是一个朋友发我的,我也不知道他在哪里弄的,我感觉挺好玩的,对反调试 异常 以及代码还原的学习有一些帮助

调试器:X64和OD

反编译工具:IDA

PE工具:Detect It Easy

反调试插件:OD的StrongOD和虫子的ScyllaHide

ARK工具:Pchunter

MFC工具:MfcSpy

初步分析

第一步先看看PE文件 工具说:软件是使用2008的MFC写的

上面得知是MFC写的软件,我们可以利用MFC的RTTI(动态类型识别)获取信息,如果不是MFC写的,我们可以运行一下软件看看,有没有报错信息

当然这个软件,输入注册码点击注册没有任何提示

 

打开调试器附加看看字符串,结果软件会闪退,无法附加,估计是有反调试,遇到这种情况我有三种方式可以解决

第一种:静态分析解决反调试

第二种:使用ARK工具把软件暂停,然后在用调试器附加

第三种:直接使用调试器打开程序,让软件断到入口或者系统断点

我们先使用第二种吧,因为X32调试器对中文字符串的支持不是很好,我没有装插件,所以先用OD看看字符串吧

验证函数中有一个异常 OD的反汇编已经出现了BUG,可以使用删除分析,我这里就不删除了 直接打开IDA F5吧 

 

虽然不能F5 但是我们可以很清晰的看到,两个GetWindowText 估计一个是获取用户名 一个是获取密码

至于为什么不能F5 是因为有一个jmp [ebx + 0xXXX] 这样的代码 IDA在解析代码的时候 它不知道跳到那里去 导致无法解析

我们直接把这个Jmp [ebp + var_8A8] 给nop掉就好了 然后删除这个函数的分析 接着在把这个函数分析为代码即可

我们可以向上看,在OD反汇编的时候也是到这个位置 反汇编失败了

下面是IDA F5后的代码 很明显 这IDA还原出来的根本不能用,这是需要我们进行修理变量的,另外我们给它重新命名一下

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

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

int __thiscall sub_401810(CWnd *this)

{

  CWnd *DlgItem; // eax

  CWnd *v2; // eax

  int result; // eax

  char *v4; // [esp+10h] [ebp-8C8h]

  CHAR *v5; // [esp+14h] [ebp-8C4h]

  unsigned int v6; // [esp+18h] [ebp-8C0h]

  unsigned __int8 v8; // [esp+21h] [ebp-8B7h]

  unsigned __int8 v9; // [esp+22h] [ebp-8B6h]

  unsigned __int8 v10; // [esp+23h] [ebp-8B5h]

  int k; // [esp+24h] [ebp-8B4h]

  int j; // [esp+28h] [ebp-8B0h]

  int i; // [esp+2Ch] [ebp-8ACh]

  int v14; // [esp+34h] [ebp-8A4h]

  int v15; // [esp+34h] [ebp-8A4h]

  char v16; // [esp+38h] [ebp-8A0h] BYREF

  int v17[6]; // [esp+39h] [ebp-89Fh] BYREF

  char v18; // [esp+51h] [ebp-887h]

  char v19; // [esp+53h] [ebp-885h]

  char v20; // [esp+54h] [ebp-884h]

  int v21; // [esp+55h] [ebp-883h]

  int v22[5]; // [esp+59h] [ebp-87Fh] BYREF

  char v23; // [esp+6Dh] [ebp-86Bh]

  int v24; // [esp+70h] [ebp-868h]

  char v25; // [esp+74h] [ebp-864h]

  int v26; // [esp+75h] [ebp-863h]

  int v27; // [esp+79h] [ebp-85Fh]

  int v28; // [esp+7Dh] [ebp-85Bh]

  int v29; // [esp+81h] [ebp-857h]

  int v30; // [esp+85h] [ebp-853h]

  int v31; // [esp+89h] [ebp-84Fh]

  char v32; // [esp+8Dh] [ebp-84Bh]

  char v33; // [esp+93h] [ebp-845h]

  char v34; // [esp+94h] [ebp-844h]

  int v35; // [esp+95h] [ebp-843h]

  int v36[5]; // [esp+99h] [ebp-83Fh] BYREF

  char v37; // [esp+ADh] [ebp-82Bh]

  CHAR String[1028]; // [esp+B0h] [ebp-828h] BYREF

  int v39; // [esp+4B4h] [ebp-424h]

  CHAR v40[1028]; // [esp+4B8h] [ebp-420h] BYREF

  CPPEH_RECORD ms_exc; // [esp+8C0h] [ebp-18h]

  MEMORY[0] = 6530;

  ms_exc.registration.TryLevel = -2;

  v33 = sub_402D60();

  v14 = sub_402C60(v33);

  sub_402750(v14);

  v26 = 0;

  v27 = 0;

  v28 = 0;

  v29 = 0;

  v30 = 0;

  v31 = 0;

  v32 = 0;

  v35 = 0;

  memset(v36, 0, sizeof(v36));

  v37 = 0;

  v21 = 0;

  memset(v22, 0, sizeof(v22));

  v23 = 0;

  v25 = 48;

  v34 = 66;

  v20 = 98;

  for ( i = 1; i < 26; ++i )

  {

    *(&v25 + i) = *((_BYTE *)&v24 + i + 3) + 1;

    *(&v34 + i) = *(&v33 + i) + 1;

    *(&v20 + i) = *(&v19 + i) + 1;

  }

  CWnd::UpdateData(this, 1);

  memset(String, 0, 1024);

  memset(v40, 0, 1024);

  ms_exc.registration.Next = (struct _EH3_EXCEPTION_REGISTRATION *)1024;

  ms_exc.exc_ptr = (EXCEPTION_POINTERS *)String;

  DlgItem = CWnd::GetDlgItem(this, 1000);

  CWnd::GetWindowTextA(DlgItem, (LPSTR)ms_exc.exc_ptr, (int)ms_exc.registration.Next);

  ms_exc.registration.Next = (struct _EH3_EXCEPTION_REGISTRATION *)1024;

  ms_exc.exc_ptr = (EXCEPTION_POINTERS *)v40;

  v2 = CWnd::GetDlgItem(this, 1001);

  result = CWnd::GetWindowTextA(v2, (LPSTR)ms_exc.exc_ptr, (int)ms_exc.registration.Next);

  if ( String[7] )

  {

    result = String[8];

    if ( !String[8] && v40[23] && !v40[24] )

    {

      v39 = 16;

      v24 = 32;

      for ( j = 0; j < 8; ++j )

      {

        String[j] ^= j;

        String[j] ^= *(_BYTE *)(j + v39);

        String[j] ^= *(_BYTE *)(j + v24);

      }

      v16 = 0;

      memset(v17, 0, sizeof(v17));

      v18 = 0;

      for ( k = 0; k < 8; ++k )

      {

        v10 = (unsigned __int8)(String[k] & 0xE0) / 32;

        v8 = (String[k] & 0x1C) / 4;

        v9 = String[k] & 3;

        if ( k % 3 == 2 )

        {

          *(&v16 + 3 * k) = *(&v25 + v9);

          *((_BYTE *)v17 + 3 * k) = *((_BYTE *)v36 + v10 + 3);

          *((_BYTE *)v17 + 3 * k + 1) = *((_BYTE *)&v22[2] + v8 + 3);

        }

        if ( k % 3 == 1 )

        {

          *(&v16 + 3 * k) = *((_BYTE *)&v36[2] + v10 + 3);

          *((_BYTE *)v17 + 3 * k) = *((_BYTE *)v22 + v8 + 3);

          *((_BYTE *)v17 + 3 * k + 1) = *(&v25 + v9);

        }

        if ( !(k % 3) )

        {

          *(&v16 + 3 * k) = *((_BYTE *)&v36[2] + v8 + 3);

          *((_BYTE *)v17 + 3 * k) = *((_BYTE *)v22 + v9 + 3);

          *((_BYTE *)v17 + 3 * k + 1) = *(&v25 + v10);

        }

      }

      sub_401790();

      v33 = sub_402D90();

      v15 = sub_402C60(v33);

      sub_4028A0(v15);

      v6 = 24;

      v5 = v40;

      v4 = &v16;

      while ( v6 >= 4 )

      {

        result = (int)v5;

        if ( *(_DWORD *)v4 != *(_DWORD *)v5 )

          return result;

        v6 -= 4;

        v5 += 4;

        v4 += 4;

      }

      return CWnd::MessageBoxA(this, &Text, 0, 0);

    }

  }

  return result;

}

1.根据循环可以知道对应数组大小和数组首地址

2.根据MemSet也可以知道对应数组的大小和数组首地址

3.根据GetWindowsText也可以知道数组的大小

修正变量要结合代码怎么去操作这个变量的 根据它的逻辑来猜测大小

这是变量重命名后的汇编代码

经过修理后的IDA F5代码 可以看到基本上很清晰了 效果跟源代码应该很接近

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

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

int __thiscall sub_401810(CWnd *this)

{

  CWnd *DlgItem; // eax

  CWnd *v2; // eax

  int result; // eax

  char *pFinalKey_1; // [esp+10h] [ebp-8C8h]

  char *pGetWindowTextString1_1; // [esp+14h] [ebp-8C4h]

  unsigned int Var24_1; // [esp+18h] [ebp-8C0h]

  unsigned __int8 Var8_1; // [esp+21h] [ebp-8B7h]

  unsigned __int8 Var9_1; // [esp+22h] [ebp-8B6h]

  unsigned __int8 Var10_1; // [esp+23h] [ebp-8B5h]

  int K; // [esp+24h] [ebp-8B4h]

  int J; // [esp+28h] [ebp-8B0h]

  int I; // [esp+2Ch] [ebp-8ACh]

  int Unknown2_1; // [esp+34h] [ebp-8A4h]

  int unknown1; // [esp+34h] [ebp-8A4h]

  char FinalKey_1[26]; // [esp+38h] [ebp-8A0h] BYREF

  char SecretKey3[28]; // [esp+54h] [ebp-884h] BYREF

  int v19; // [esp+70h] [ebp-868h]

  char SecretKey1[31]; // [esp+74h] [ebp-864h] BYREF

  char Unknown3_1; // [esp+93h] [ebp-845h]

  char SecretKey2[28]; // [esp+94h] [ebp-844h] BYREF

  char GetWindowTextString2_1[1028]; // [esp+B0h] [ebp-828h] BYREF

  int v24; // [esp+4B4h] [ebp-424h]

  char GetWindowTextString1[1028]; // [esp+4B8h] [ebp-420h] BYREF

  CPPEH_RECORD ms_exc; // [esp+8C0h] [ebp-18h]

  MEMORY[0] = 6530;

  ms_exc.registration.TryLevel = -2;

  Unknown3_1 = sub_402D60();

  Unknown2_1 = sub_402C60(&dword_42FA04, Unknown3_1);

  sub_402750(Unknown2_1);

  memset(&SecretKey1[1], 0, 25);

  memset(&SecretKey2[1], 0, 25);

  memset(&SecretKey3[1], 0, 25);

  SecretKey1[0] = 48;

  SecretKey2[0] = 66;

  SecretKey3[0] = 98;

  for ( I = 1; I < 26; ++I )

  {

    SecretKey1[I] = SecretKey1[I - 1] + 1;

    SecretKey2[I] = SecretKey2[I - 1] + 1;

    SecretKey3[I] = SecretKey3[I - 1] + 1;

  }

  CWnd::UpdateData(this, 1);

  memset(GetWindowTextString2_1, 0, 1024);

  memset(GetWindowTextString1, 0, 1024);

  ms_exc.registration.Next = (struct _EH3_EXCEPTION_REGISTRATION *)1024;

  ms_exc.exc_ptr = (EXCEPTION_POINTERS *)GetWindowTextString2_1;

  DlgItem = CWnd::GetDlgItem(this, 1000);

  CWnd::GetWindowTextA(DlgItem, (LPSTR)ms_exc.exc_ptr, (int)ms_exc.registration.Next);

  ms_exc.registration.Next = (struct _EH3_EXCEPTION_REGISTRATION *)1024;

  ms_exc.exc_ptr = (EXCEPTION_POINTERS *)GetWindowTextString1;

  v2 = CWnd::GetDlgItem(this, 1001);

  result = CWnd::GetWindowTextA(v2, (LPSTR)ms_exc.exc_ptr, (int)ms_exc.registration.Next);

  if ( GetWindowTextString2_1[7] )

  {

    result = GetWindowTextString2_1[8];

    if ( !GetWindowTextString2_1[8] && GetWindowTextString1[23] && !GetWindowTextString1[24] )

    {

      v24 = 16;

      v19 = 32;

      for ( J = 0; J < 8; ++J )

      {

        GetWindowTextString2_1[J] ^= J;

        GetWindowTextString2_1[J] ^= *(_BYTE *)(J + v24);

        GetWindowTextString2_1[J] ^= *(_BYTE *)(J + v19);

      }

      memset(FinalKey_1, 0, sizeof(FinalKey_1));

      for ( K = 0; K < 8; ++K )

      {

        Var10_1 = (unsigned __int8)(GetWindowTextString2_1[K] & 0xE0) / 32;

        Var8_1 = (GetWindowTextString2_1[K] & 0x1C) / 4;

        Var9_1 = GetWindowTextString2_1[K] & 3;

        if ( K % 3 == 2 )

        {

          FinalKey_1[3 * K] = SecretKey1[Var9_1];

          FinalKey_1[3 * K + 1] = SecretKey2[Var10_1 + 8];

          FinalKey_1[3 * K + 2] = SecretKey3[Var8_1 + 16];

        }

        if ( K % 3 == 1 )

        {

          FinalKey_1[3 * K] = SecretKey2[Var10_1 + 16];

          FinalKey_1[3 * K + 1] = SecretKey3[Var8_1 + 8];

          FinalKey_1[3 * K + 2] = SecretKey1[Var9_1];

        }

        if ( !(K % 3) )

        {

          FinalKey_1[3 * K] = SecretKey2[Var8_1 + 16];

          FinalKey_1[3 * K + 1] = SecretKey3[Var9_1 + 8];

          FinalKey_1[3 * K + 2] = SecretKey1[Var10_1];

        }

      }

      sub_401790();

      Unknown3_1 = sub_402D90();

      unknown1 = sub_402C60(&dword_42FA04, Unknown3_1);

      sub_4028A0(unknown1);

      Var24_1 = 24;

      pGetWindowTextString1_1 = GetWindowTextString1;

      pFinalKey_1 = FinalKey_1;

      while ( Var24_1 >= 4 )

      {

        result = (int)pGetWindowTextString1_1;

        if ( *(_DWORD *)pFinalKey_1 != *(_DWORD *)pGetWindowTextString1_1 )

          return result;

        Var24_1 -= 4;

        pGetWindowTextString1_1 += 4;

        pFinalKey_1 += 4;

      }

      return CWnd::MessageBoxA(this, &Text, 0, 0);

    }

  }

  return result;

}

我们可以看到上面的代码中还是有两个变量的值是错误的 一个是V24 一个是V19 为什么是错误的呢?

我们可以结合下面的循环代码,下面代码中用到V24 是*(BYTE*)(J+V24);    用到V19 是*(BYTE*)(J+V19);

这很明显是一个数组 大小是8个字节

看下面代码中 V19和V24是来源于AbnormalVariable这个变量的值 + 16和+32的位置的

这也就是下面代码中V19和V24数组的值的来源

最终的C代码 算法还原完成

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

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

int main()

{

    char SecretKey1[28];

    char SecretKey2[28];

    char SecretKey3[28];

    memset(SecretKey1,0,sizeof(SecretKey1));

    memset(SecretKey2,0,sizeof(SecretKey2));

    memset(SecretKey3,0,sizeof(SecretKey3));

    SecretKey1[0] = 48;

    SecretKey2[0] = 66;

    SecretKey3[0] = 98;

    for (int I = 1; I < 26; ++I)

    {

        SecretKey1[I] = SecretKey1[I - 1] + 1;

        SecretKey2[I] = SecretKey2[I - 1] + 1;

        SecretKey3[I] = SecretKey3[I - 1] + 1;

    }

    char GetWindowTextString1[1024];

    char GetWindowTextString2_1[1024];

    memset(GetWindowTextString1,0,1024);

    memset(GetWindowTextString2_1, 0, 1024);

    strcpy(GetWindowTextString2_1,"12345678");

    char v24[24] = { 0x00,0x00,0x88,0x85,0xBB,0xF7,0xFF,0xFF,0x0F,0xB6,0x8D,0xBB,0xF7,0xFF,0xFF,0xB8,0x04,0xFA,0x42,0x00,0xE8,0xAD };

    char v19[24] = { 0xB8,0x04,0xFA,0x42,0x00,0xE8,0xAD,0x13,0x00,0x00,0x89,0x85,0x5C,0xF7,0xFF,0xFF,0x8B,0x95,0x5C,0xF7,0xFF,0xFF };

    for (int J = 0; J < 8; ++J)

    {

        GetWindowTextString2_1[J] ^= J;

        GetWindowTextString2_1[J] ^= v24[J];

        GetWindowTextString2_1[J] ^= v19[J];

    }

    char FinalKey_1[26];

    memset(FinalKey_1,0,sizeof(FinalKey_1));

    for (int K = 0; K < 8; ++K)

    {

        char Var10_1 = (unsigned __int8)(GetWindowTextString2_1[K] & 0xE0) / 32;

        char Var8_1 = (GetWindowTextString2_1[K] & 0x1C) / 4;

        char Var9_1 = GetWindowTextString2_1[K] & 3;

        if (K % 3 == 2)

        {

            FinalKey_1[3 * K] = SecretKey1[Var9_1];

            FinalKey_1[3 * K + 1] = SecretKey2[Var10_1 + 8];

            FinalKey_1[3 * K + 2] = SecretKey3[Var8_1 + 16];

        }

        if (K % 3 == 1)

        {

            FinalKey_1[3 * K] = SecretKey2[Var10_1 + 16];

            FinalKey_1[3 * K + 1] = SecretKey3[Var8_1 + 8];

            FinalKey_1[3 * K + 2] = SecretKey1[Var9_1];

        }

        if (!(K % 3))

        {

            FinalKey_1[3 * K] = SecretKey2[Var8_1 + 16];

            FinalKey_1[3 * K + 1] = SecretKey3[Var9_1 + 8];

            FinalKey_1[3 * K + 2] = SecretKey1[Var10_1];

        }

    }

    //FinalKey_1 = 0x00aff3f8 "Tk4So33LrVj7Vl20KuRm3Xn3"

    system("pause");

    return 0;

}

1

2

用户名:12345678

注册码:Tk4So33LrVj7Vl20KuRm3Xn3

 

相关文章:

MFC逆向之CrackMe Level3 过反调试 + 写注册机

今天我来分享一下,过反调试的方法以及使用IDA还原代码 写注册机的过程 由于内容太多,我准备分为两个帖子写,这个帖子主要是写IDA还原代码,下一个帖子是写反调试的分析以及过反调试和异常 这个CrackMe Level3是一个朋友发我的,我也不知道他在哪里弄的,我感觉挺好玩的,对反调试…...

【Centos】

一、Virtualbox安装Centos 1、Virtualbox 下载地址: Virtualbox 2、Centos 下载地址: Centos 3、Virtualbox安装Centos教程 Virtualbox安装Centos教程: Virtualbox安装Centos教程...

1+X大数据平台运维职业技能等级证书中级

hadoop&#xff1a; 由于我的功能限制&#xff0c;我无法直接为您执行这些操作或提供实际的截图。但我可以为您提供一步步的指导&#xff0c;帮助您完成这些任务。 1. 解压JDK安装包到“/usr/local/src”路径&#xff0c;并配置环境变量。 - 解压JDK&#xff1a;tar -zxf jd…...

网络基础(五):网络层协议介绍

目录 一、网络层 1、网络层的概念 2、网络层功能 3、IP数据包格式 二、ICMP协议 1、ICMP的作用和功能 2、ping命令的使用 2.1ping命令的通用格式 2.2ping命令的常用参数 2.3TypeCode&#xff1a;查看不同功能的ICMP报文 2.4ping出现问题 3、Tracert 4、冲突域 5、…...

浅显易懂 @JsonIgnore 的作用

1.JsonIgnore作用   在json序列化/反序列化时将java bean中使用了该注解的属性忽略掉 2.这个注解可以用在类/属性上   例如&#xff1a;在返回user对象时&#xff0c;在pwd属性上使用这个注解&#xff0c;返回user对象时会直接去掉pwd这个字段&#xff0c;不管这个属性有没…...

【计算机设计大赛作品】诗意千年—唐朝诗人群像的数字展现_附源码—信息可视化赛道获奖项目深入剖析【可视化项目案例-20】

🎉🎊🎉 你的技术旅程将在这里启航! 记得看本专栏里顶置的可视化宝典导航贴哦! 🚀🚀 本专栏为可视化专栏,包含现有的所有可视化技术。订阅专栏用户在文章底部可下载对应案例完整源码以供大家深入的学习研究。 🎓 每一个案例都会提供完整代码和详细的讲解,不论你…...

「Swift」Xcode多Target创建

前言&#xff1a;我们日常开发中会使用多个环境&#xff0c;如Dev、UAT&#xff0c;每个环境对应的业务功能都不同&#xff0c;但每个环境之间都只存在较小的差异&#xff0c;所以此时可以使用创建多个Target来实现&#xff0c;每个Target对应这个一个App&#xff0c;可以实现一…...

Python文件命名规则:批量重命名与规则匹配的文件

我从一个旧的 iOS 项目中获得了一个文件夹&#xff0c;其中包含许多类似于 image.png image2x.png another-image.png another-image2x.png然而&#xff0c;由于该项目现在只需要 2x.png 图像&#xff0c;我已经删除了所有的文件没有 2x 的名称。 但是我现在想知道如何轻松…...

『npm』一条命令快速配置npm淘宝国内镜像

&#x1f4e3;读完这篇文章里你能收获到 一条命令快速切换至淘宝镜像恢复官方镜像 文章目录 一、设置淘宝镜像源二、恢复官方镜像源三、查看当前使用的镜像 一、设置淘宝镜像源 npm config set registry https://registry.npm.taobao.org服务器建议全局设置 sudo npm config…...

Java EE 多线程之线程安全的集合类

文章目录 1. 多线程环境使用 ArrayList1. 1 Collections.synchronizedList(new ArrayList)1.2 CopyOnWriteArrayList 2. 多线程环境使用队列2.1 ArrayBlockingQueue2.2 LinkedBlockingQueue2.3 PriorityBlockingQueue2.4 TransferQueue 3. 多线程环境使用哈希表3.1 Hashtable3.…...

明明随机数

明明想在学校中请一些同学一起做一项问卷调查&#xff0c;为了实验的客观性&#xff0c;他先用计算机生成了N个1到1000之间的随机整数(N<100)&#xff0c;对于其中重复的数字&#xff0c;只保留一个&#xff0c;把其余相同的数去掉&#xff0c;不同的数对应着不同的学生的学…...

优思学院|如何建立公司运营指标体系?如何推行六西格玛改进运营指标?

关键绩效指标 (KPI) 是测量您团队或组织朝重要商业目标进展表现如何的量化指标&#xff0c;组织会在多个层面使用 KPI&#xff0c;这视乎您想要追踪何指标而定&#xff0c;您可以设定全组织的、特定团队的、或甚至是个人 KPI。 良好的KPI能让公司管理者掌握组织的营运是否进度…...

vue2 echarts不同角色多个类型数据的柱状图

前端代码&#xff1a; 先按照echarts插件。在页面里引用 import * as echarts from "echarts";设置div <div style"width:100%;height:250px;margin-top: 4px;" id"addressChart"></div>方法: addressEcharts() {const option {g…...

Mysql表的数据类型

数据类型 https://www.sjkjc.com/mysql/varchar/ MySQL 中的数据类型包括以下几个大类&#xff1a; 字符串类型 数字类型 日期和时间类型 二进制类型 地理位置数据类型 JSON 数据类型 MySQL 字符串数据类型 VARCHAR&#xff1a;纯文本字符串&#xff0c;字符串长度是可变的…...

c语言单向链表

看如下代码&#xff0c;这是一个完整的可运行的c源文件&#xff0c;要注意的点&#xff1a; c语言程序运行不一定需要头文件NULL其实是 (void*)0&#xff0c;把指针赋值成(void*)0,就是防止程序员不想该指针被引用的时候被引用&#xff0c;引用地址为0的值程序会引起系统中断&…...

『番外篇三』Swift “乱弹”之带索引遍历异步序列(AsyncSequence)

概览 在 Swift 开发中,我们往往在遍历集合元素的同时希望获得元素对应的索引。在本课中,我们将向小伙伴们展示除 enumerated() 方法之外的几种实现思路。在玩转普通集合之后,我们将用“魔法棒”进一步搞定异步序列带索引遍历的实现。 在本篇博主中,您将学到以下内容: 概…...

学习JVM

java虚拟机 流程&#xff1a;helloworld.java----(javac编译)----helloworld.class-------(java运行)——JVM——机器码JVM功能 *解释和运行 *内存管理 *即时编译&#xff08;跨平台-慢一点&#xff09;jit &#xff08;反复用到的代码 解释保存再内存里面&#xff09;…...

Oracle MongoDB

听课的时候第一次碰到&#xff0c;可以了解一下吧&#xff0c;就直接开了墨者学院的靶场 #oracle数据库 Oracle数据库注入全方位利用 - 先知社区 这篇写的真的很好 1.判断注入点 当时找了半天没找到 看样子是找到了&#xff0c;测试一下看看 id1 and 11 时没有报错 2.判断字段…...

Linux-RedHat系统-安装 中间件 Tuxedo

安装步聚 一、中间件安装包&#xff1a; tuxedo121300_64_Linux_01_x86 Tuxedo下载地址&#xff1a; Oracle Tuxedo Downloads 二、新建用户&#xff1a; &#xff08;创建Oracle用户时&#xff0c;需要root权限操作&#xff09; 创建用户&#xff1a; # useradd oracle …...

PHP中的依赖注入是怎样的?

依赖注入&#xff08;Dependency Injection&#xff0c;DI&#xff09;是一种设计模式&#xff0c;它用于解耦组件之间的依赖关系&#xff0c;提高代码的可维护性、可测试性和灵活性。在 PHP 中&#xff0c;依赖注入通常通过构造函数注入、方法注入或属性注入来实现。 以下是依…...

UE5 学习系列(二)用户操作界面及介绍

这篇博客是 UE5 学习系列博客的第二篇&#xff0c;在第一篇的基础上展开这篇内容。博客参考的 B 站视频资料和第一篇的链接如下&#xff1a; 【Note】&#xff1a;如果你已经完成安装等操作&#xff0c;可以只执行第一篇博客中 2. 新建一个空白游戏项目 章节操作&#xff0c;重…...

基于距离变化能量开销动态调整的WSN低功耗拓扑控制开销算法matlab仿真

目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.算法仿真参数 5.算法理论概述 6.参考文献 7.完整程序 1.程序功能描述 通过动态调整节点通信的能量开销&#xff0c;平衡网络负载&#xff0c;延长WSN生命周期。具体通过建立基于距离的能量消耗模型&am…...

土地利用/土地覆盖遥感解译与基于CLUE模型未来变化情景预测;从基础到高级,涵盖ArcGIS数据处理、ENVI遥感解译与CLUE模型情景模拟等

&#x1f50d; 土地利用/土地覆盖数据是生态、环境和气象等诸多领域模型的关键输入参数。通过遥感影像解译技术&#xff0c;可以精准获取历史或当前任何一个区域的土地利用/土地覆盖情况。这些数据不仅能够用于评估区域生态环境的变化趋势&#xff0c;还能有效评价重大生态工程…...

三体问题详解

从物理学角度&#xff0c;三体问题之所以不稳定&#xff0c;是因为三个天体在万有引力作用下相互作用&#xff0c;形成一个非线性耦合系统。我们可以从牛顿经典力学出发&#xff0c;列出具体的运动方程&#xff0c;并说明为何这个系统本质上是混沌的&#xff0c;无法得到一般解…...

Java入门学习详细版(一)

大家好&#xff0c;Java 学习是一个系统学习的过程&#xff0c;核心原则就是“理论 实践 坚持”&#xff0c;并且需循序渐进&#xff0c;不可过于着急&#xff0c;本篇文章推出的这份详细入门学习资料将带大家从零基础开始&#xff0c;逐步掌握 Java 的核心概念和编程技能。 …...

关于 WASM:1. WASM 基础原理

一、WASM 简介 1.1 WebAssembly 是什么&#xff1f; WebAssembly&#xff08;WASM&#xff09; 是一种能在现代浏览器中高效运行的二进制指令格式&#xff0c;它不是传统的编程语言&#xff0c;而是一种 低级字节码格式&#xff0c;可由高级语言&#xff08;如 C、C、Rust&am…...

图表类系列各种样式PPT模版分享

图标图表系列PPT模版&#xff0c;柱状图PPT模版&#xff0c;线状图PPT模版&#xff0c;折线图PPT模版&#xff0c;饼状图PPT模版&#xff0c;雷达图PPT模版&#xff0c;树状图PPT模版 图表类系列各种样式PPT模版分享&#xff1a;图表系列PPT模板https://pan.quark.cn/s/20d40aa…...

Spring AI与Spring Modulith核心技术解析

Spring AI核心架构解析 Spring AI&#xff08;https://spring.io/projects/spring-ai&#xff09;作为Spring生态中的AI集成框架&#xff0c;其核心设计理念是通过模块化架构降低AI应用的开发复杂度。与Python生态中的LangChain/LlamaIndex等工具类似&#xff0c;但特别为多语…...

视觉slam十四讲实践部分记录——ch2、ch3

ch2 一、使用g++编译.cpp为可执行文件并运行(P30) g++ helloSLAM.cpp ./a.out运行 二、使用cmake编译 mkdir build cd build cmake .. makeCMakeCache.txt 文件仍然指向旧的目录。这表明在源代码目录中可能还存在旧的 CMakeCache.txt 文件,或者在构建过程中仍然引用了旧的路…...

CVE-2020-17519源码分析与漏洞复现(Flink 任意文件读取)

漏洞概览 漏洞名称&#xff1a;Apache Flink REST API 任意文件读取漏洞CVE编号&#xff1a;CVE-2020-17519CVSS评分&#xff1a;7.5影响版本&#xff1a;Apache Flink 1.11.0、1.11.1、1.11.2修复版本&#xff1a;≥ 1.11.3 或 ≥ 1.12.0漏洞类型&#xff1a;路径遍历&#x…...