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

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/225034.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Docker笔记:Docker Swarm, Consul, Gateway, Microservices 集群部署

关于 Consul 服务 Consul是Go语言写的开源的服务发现软件Consul具有服务发现、健康检查、 服务治理、微服务熔断处理等功能 Consul 部署方式1: 直接在linux 上面部署 consul 集群 1 &#xff09;下载 在各个服务器上 下载 consul 后解压并将其目录配置到环境变量中&#xff…

VMP泄露编译的一些注意事项

VMP编译教程 鉴于VMP已经在GitHub上被大佬强制开源&#xff0c;特此出一期编译教程。各位熟悉的可以略过&#xff0c;不熟悉的可以参考一下。 环境&#xff08;软件&#xff09; Visual Studio 2015 - 2022 &#xff08;建议使用VS2019&#xff0c;Qt插件只有这个版本及以上…

vscode的文件和文件夹的警告标志如何消去

由于平时用vscode写一些java的小demo, 但是这个vscode的警告和错误管理很奇怪, 这个警告信息会显示在这个侧边的文件和文件夹中, 我上网上找能不能把这个给去掉的办法, 找了半天没找到。 于是我就自己去查了一下这个vscode的设置, 真让我找到了这方面的开关, 把下面的这个关闭…

Linux学习笔记-Ubuntu下ssh服务器连接异常Connection reset

文章目录 一、问题问题现象1.1 连接重置无法访问的的问题1.2 查看服务器连接状态1.3 使用调试模式查看的信息 二、临时解决方法三、从根源解决问题3.1 问题分析3.2 服务器的ssh日志3.3 修改ssh配置禁止root登录3.4 配置允许所有ip访问3.5 修改认证方法 角色&#xff1a;百世经纶…

selenium+xpath爬取二手房标题

贝壳找房标题爬取需要注意的是&#xff0c;在页面中间有一个小广告 而他就在ul的li下面&#xff0c;当我们进行title所以输出时&#xff0c;会报错。 所以在进行页面解析之前必须把广告叉掉&#xff0c;不然也把广告那一部分的li给爬取下来了 所以&#xff0c;我们&#xff0…

弹性架构:容错系统策略

如今软件无处不在 - 从我们的手机到汽车和电器。这意味着软件系统的可靠性、健壮性和弹性非常重要。 弹性系统可以承受故障或错误而不会完全崩溃。容错能力是弹性的关键部分。即使出现问题&#xff0c;它也能让系统保持正常工作。 在本文中&#xff0c;我们将了解为什么弹性和…

JsRpc技术服务搭建,最简单的JSRPC,Flask+undetected-chromedriver

只需10来行代码快速实现JSRpc&#xff0c;最简单的JSRPC 使用Flask和undetected-chromedriver快速实现JsRpc 推荐Python版本3.7.x及以上&#xff0c;需要pip安装 pip install Flask pip install undetected-chromedriver __author__ jiuLiang __email__ "jiuliangef…

软件测试职业规划

软件测试人员的发展误区【4】 公司开发的产品专业性较强&#xff0c;软件测试人员需要有很强的专业知识&#xff0c;现在软件测试人员发展出现了一种测试管理者不愿意看到的景象&#xff1a; 1、开发技术较强的软件测试人员转向了软件开发(非测试工具开发)&#xff1b; 2、业务…

蓝桥杯专题-真题版含答案-【古代赌局】【古堡算式】【微生物增殖】【密码发生器】

Unity3D特效百例案例项目实战源码Android-Unity实战问题汇总游戏脚本-辅助自动化Android控件全解手册再战Android系列Scratch编程案例软考全系列Unity3D学习专栏蓝桥系列ChatGPT和AIGC &#x1f449;关于作者 专注于Android/Unity和各种游戏开发技巧&#xff0c;以及各种资源分…

K中期考核-降低显存的关键

读入模型参数-且不占用显卡 see_memory_usage(‘message’) # 4. 读入checkpiont参数 state_dicttorch.load(../train-output/ args.model_name_or_path.split(/)[-1] /unet/diffusion_pytorch_model.bin, map_locationcpu) # state_dicttorch.load(../train-output/ …

C++报错:error C2238: 意外的标记位于“;”之前

报错信息如下&#xff1a; 编译遇见这样的错误信息主要有一下几种&#xff1a; 情况一&#xff1a; 多数情况下出现这种问题的原因是因为头文件重复包含&#xff1a;即头文件A包含了B&#xff0c;头文件B又包含了A&#xff0c;导致编译器在加载头文件时陷入死循环。 解决办法…

力扣题:数字与字符串间转换-12.16

力扣题-12.16 [力扣刷题攻略] Re&#xff1a;从零开始的力扣刷题生活 力扣题1&#xff1a;640. 求解方程 解题思想&#xff1a;首先将方程按照“”进行划分&#xff0c;然后分别记录x的因数和常数项&#xff0c;最后进行返回的判断即可 class Solution(object):def solveEqu…

Ubuntu下COLMAP的编译与安装全攻略

文章目录 一、前言二、安装依赖库基本的依赖安装Ceres Solver安装不需要cuda支持需要cuda支持 三、编译colmap四、运行colmap五、总结 一、前言 在计算机视觉领域&#xff0c;colmap是一款功能强大的开源图像重建工具。它提供了包括SfM&#xff08;Structure from Motion&…

git变更关联的远程仓库

git变更关联的远程仓库 git 将本地关联的远程仓库1变更为新建的远程仓库2 1、移除本地的远程仓库关联关系 git remote remove origin 2、添加新的远程仓库地址&#xff1a; git remote add origin gitgithub.com:github-xiaobai/66-test-cc.git 3、生成本机的ssh-key(如果已…

uniapp获取app版本号、h5版本号、微信小程序版本号的方法

目录 第一种获取App版本号App版本号App的H5版本号 第二种获取App版本号第三种获取App版本号第一种获取微信小程序版本号获取微信小程序版本号 最后 第一种获取App版本号 App版本号 // 获取当前app的版本 const systemInfo uni.getSystemInfoSync(); // 应用程序版本号 // 条…

万户 OA OfficeServer.jsp 任意文件上传漏洞复现

0x01 产品简介 万户OA是面向政府组织及企事业单位的FlexOffice自主安全协同办公平台。 0x02 漏洞概述 万户OA OfficeServer.jsp接口存在任意文件上传漏洞,攻击者可通过该漏洞上传任意文件从而控制整个服务器。 0x03 复现环境 FOFA: (banner="OASESSIONID" &a…

算法基础概念之数据结构

邻接表 每个点作为头节点接一条链表 链表中元素均为该头节点指向的点 优先队列 参数: ①储存元素类型 ②底层使用的存储结构(一般为vector) ③比较方式(默认小于)

ffmpeg可以做什么

用途 FFmpeg是一个功能强大的多媒体处理工具&#xff0c;可以处理音频和视频文件。它是一个开源项目&#xff0c;可在各种操作系统上运行&#xff0c;包括Linux、Windows和Mac OS X等。以下是FFmpeg可以做的一些主要任务&#xff1a; 转换媒体格式&#xff1a;可将一个媒体格式…

0基础学习VR全景平台篇第128篇:720VR全景拍摄设备推荐

上课&#xff01;全体起立~ 大家好&#xff0c;欢迎观看蛙色官方系列全景摄影课程&#xff01; 本篇教程&#xff0c;小编为大家推荐720VR全景拍摄所需要的设备器材。上节我们提到&#xff0c;理论上任意相机和镜头都能够拍摄全景&#xff0c;但为了标准化制作流程&#xff0…

关于chatgpt一点肤浅认识

001 词向量 用数字向量表示单词。它是计算机更好地理解单词 1、预训练 – 就是先训练一个模型&#xff0c;用于以后特定任务的微调&#xff0c;比如将 BERT这个模型用于特定的NLP任务&#xff0c;比如情感分析 2、one-hot: 用只有一个元素是1&#xff0c;其他是0的向量表示物体…