• 逆向-还原代码之split (Intel 64)


    #include
    #include <stdlib.h>
    #include

    void a_1()
    {
        /*1169:    f3 0f 1e fa              endbr64
        116d:    55                       push   %rbp
        116e:    48 89 e5                 mov    %rsp,%rbp
        1171:    48 83 ec 30              sub    $0x30,%rsp
        1175:    64 48 8b 04 25 28 00     mov    %fs:0x28,%rax
        117c:    00 00
        117e:    48 89 45 f8              mov    %rax,-0x8(%rbp)
        1182:    31 c0                    xor    %eax,%eax
        1184:    48 c7 45 f0 01 00 00     movq   $0x1,-0x10(%rbp)
        118b:    00
        118c:    c7 45 dc 02 00 00 00     movl   $0x2,-0x24(%rbp)*/
            long j = 0x1;
            int i = 2;

        /*1193:    c7 45 e0 00 00 00 00     movl   $0x0,-0x20(%rbp)
        119a:    8b 45 e0                 mov    -0x20(%rbp),%eax
        119d:    89 45 e4                 mov    %eax,-0x1c(%rbp)
        11a0:    8b 45 e4                 mov    -0x1c(%rbp),%eax
        11a3:    89 45 e8                 mov    %eax,-0x18(%rbp)
        11a6:    8b 45 e8                 mov    -0x18(%rbp),%eax
        11a9:    89 45 ec                 mov    %eax,-0x14(%rbp)*/
            int a[4];
            a[0] = a[1] = a[2] = a[3] = 0;

        /*11ac:    48 8b 45 f0              mov    -0x10(%rbp),%rax
        11b0:    48 89 c6                 mov    %rax,%rsi
        11b3:    48 8d 3d 4e 0e 00 00     lea    0xe4e(%rip),%rdi        # 2008 <_IO_stdin_used+0x8>
        11ba:    b8 00 00 00 00           mov    $0x0,%eax
        11bf:    e8 ac fe ff ff           callq  1070 */
            printf("%ld\n", j);

        /*11c4:    48 8d 45 f0              lea    -0x10(%rbp),%rax
        11c8:    48 89 c6                 mov    %rax,%rsi
        11cb:    48 8d 3d 36 0e 00 00     lea    0xe36(%rip),%rdi        # 2008 <_IO_stdin_used+0x8>
        11d2:    b8 00 00 00 00           mov    $0x0,%eax
        11d7:    e8 94 fe ff ff           callq  1070 */
            printf("%lx\n", (long)&j);

        /*11dc:    48 8b 45 f0              mov    -0x10(%rbp),%rax        // rax = j
        11e0:    48 8d 70 14              lea    0x14(%rax),%rsi        // rsi = j+0x14
            a[0] = j+
        11e4:    48 8b 45 f0              mov    -0x10(%rbp),%rax        // rax = j
        11e8:    4c 8d 40 10              lea    0x10(%rax),%r8        // r8 = j+0x10
        11ec:    48 8b 45 f0              mov    -0x10(%rbp),%rax        // rax = j
        11f0:    48 8d 78 0c              lea    0xc(%rax),%rdi        // rdi = j+c
        11f4:    48 8b 45 f0              mov    -0x10(%rbp),%rax        // rax = j
        11f8:    48 8d 48 08              lea    0x8(%rax),%rcx        // rcx = j+8
        11fc:    48 8b 45 f0              mov    -0x10(%rbp),%rax        // rax = j
        1200:    48 8d 50 04              lea    0x4(%rax),%rdx        // rdx = j+4
        1204:    48 8b 45 f0              mov    -0x10(%rbp),%rax        // rax = j
        1208:    48 83 ec 08              sub    $0x8,%rsp            // rsp = rsp-8
        120c:    56                       push   %rsi
        120d:    4d 89 c1                 mov    %r8,%r9                // r9 = j+0x10
        1210:    49 89 f8                 mov    %rdi,%r8                // r8 = j+0xc
        1213:    48 89 c6                 mov    %rax,%rsi            // rsi = j
        1216:    48 8d 3d f3 0d 00 00     lea    0xdf3(%rip),%rdi        # 2010 <_IO_stdin_used+0x10>
        121d:    b8 00 00 00 00           mov    $0x0,%eax
        1222:    e8 49 fe ff ff           callq  1070 */
            printf("%d %d %d %d %d %d\n", j, j+0x4, j+0x8, j+0xc, j+0x10, j+0x14);

        /*1227:    48 83 c4 10              add    $0x10,%rsp
        122b:    48 8b 45 f0              mov    -0x10(%rbp),%rax        // rax = j
        122f:    89 45 ec                 mov    %eax,-0x14(%rbp)        // (rbp-0x14) = j
            a[0] = j;
        1232:    48 8b 45 f0              mov    -0x10(%rbp),%rax        // rax = j
        1236:    48 83 c0 04              add    $0x4,%rax            // rax = j+4
        123a:    89 45 e8                 mov    %eax,-0x18(%rbp)        // (rbp-0x18) = j+4
            a[1] = j + 4;

        123d:    48 8b 45 f0              mov    -0x10(%rbp),%rax        // rax = j
        1241:    48 83 c0 08              add    $0x8,%rax            // rax = j+8
        1245:    89 45 e4                 mov    %eax,-0x1c(%rbp)        // (rbp-0x1c) = j+8
            a[2] = j + 8;

        1248:    48 8b 45 f0              mov    -0x10(%rbp),%rax        // rax = j
        124c:    48 83 c0 0c              add    $0xc,%rax            // rax = j+0xc
        1250:    89 45 e0                 mov    %eax,-0x20(%rbp)        // (rbp-0x20) = j+0xc
            a[3] = j + 0xc;

        1253:    8b 75 e0                 mov    -0x20(%rbp),%esi        
        1256:    8b 4d e4                 mov    -0x1c(%rbp),%ecx
        1259:    8b 55 e8                 mov    -0x18(%rbp),%edx
        125c:    8b 45 ec                 mov    -0x14(%rbp),%eax
        125f:    41 89 f0                 mov    %esi,%r8d
        1262:    89 c6                    mov    %eax,%esi
        1264:    48 8d 3d c4 0d 00 00     lea    0xdc4(%rip),%rdi        # 202f <_IO_stdin_used+0x2f>
        126b:    b8 00 00 00 00           mov    $0x0,%eax
        1270:    e8 fb fd ff ff           callq  1070 */
            a[0] = j;
            a[1] = j + 4;
            a[2] = j + 8;
            a[3] = j + 0xc;
            printf("%d %d %d %d\n", a[0], a[1], a[2], a[3]);

        /*1275:    48 8d 45 dc              lea    -0x24(%rbp),%rax        // rax = &i
        1279:    48 89 45 f0              mov    %rax,-0x10(%rbp)        // (rpb-0x10) = &i */
            j = &i;

        /*127d:    48 8d 45 dc              lea    -0x24(%rbp),%rax        // rax = &i
        1281:    48 89 c6                 mov    %rax,%rsi            // rsi = &i
        1284:    48 8d 3d b1 0d 00 00     lea    0xdb1(%rip),%rdi        # 203c <_IO_stdin_used+0x3c>
        128b:    b8 00 00 00 00           mov    $0x0,%eax
        1290:    e8 db fd ff ff           callq  1070 */
            printf("%lx\n", (long)&i);

        /*1295:    48 8b 45 f0              mov    -0x10(%rbp),%rax
        1299:    48 89 c6                 mov    %rax,%rsi
        129c:    48 8d 3d 65 0d 00 00     lea    0xd65(%rip),%rdi        # 2008 <_IO_stdin_used+0x8>
        12a3:    b8 00 00 00 00           mov    $0x0,%eax
        12a8:    e8 c3 fd ff ff           callq  1070 */
            printf("%lx\n", j);

        /*12ad:    48 8b 45 f0              mov    -0x10(%rbp),%rax
        12b1:    8b 00                    mov    (%rax),%eax
        12b3:    89 c6                    mov    %eax,%esi
        12b5:    48 8d 3d 4c 0d 00 00     lea    0xd4c(%rip),%rdi        # 2008 <_IO_stdin_used+0x8>
        12bc:    b8 00 00 00 00           mov    $0x0,%eax
        12c1:    e8 aa fd ff ff           callq  1070 */
            printf("%d\n", *(int*)j);

        /*12c6:    90                       nop
        12c7:    48 8b 45 f8              mov    -0x8(%rbp),%rax
        12cb:    64 48 33 04 25 28 00     xor    %fs:0x28,%rax
        12d2:    00 00
        12d4:    74 05                    je     12db
        12d6:    e8 85 fd ff ff           callq  1060 <__stack_chk_fail@plt>
        12db:    c9                       leaveq
        12dc:    c3                       retq */  
    }

    void a_0()
    {
        /*12dd:    f3 0f 1e fa              endbr64
        12e1:    55                       push   %rbp
        12e2:    48 89 e5                 mov    %rsp,%rbp
        12e5:    48 83 ec 20              sub    $0x20,%rsp
        12e9:    64 48 8b 04 25 28 00     mov    %fs:0x28,%rax
        12f0:    00 00
        12f2:    48 89 45 f8              mov    %rax,-0x8(%rbp)
        12f6:    31 c0                    xor    %eax,%eax
        12f8:    48 c7 45 f0 00 00 00     movq   $0x0,-0x10(%rbp) */
        long j = 0;

        /*12ff:    00
        1300:    c7 45 e0 00 00 00 00     movl   $0x0,-0x20(%rbp)
        1307:    8b 45 e0                 mov    -0x20(%rbp),%eax
        130a:    89 45 e4                 mov    %eax,-0x1c(%rbp)
        130d:    8b 45 e4                 mov    -0x1c(%rbp),%eax
        1310:    89 45 e8                 mov    %eax,-0x18(%rbp)
        1313:    8b 45 e8                 mov    -0x18(%rbp),%eax
        1316:    89 45 ec                 mov    %eax,-0x14(%rbp) */
        int a[4];
        a[0] = a[1] = a[2] = a[3] = 0;

        /*1319:    48 8b 45 f0              mov    -0x10(%rbp),%rax
        131d:    48 89 c6                 mov    %rax,%rsi
        1320:    48 8d 3d e1 0c 00 00     lea    0xce1(%rip),%rdi        # 2008 <_IO_stdin_used+0x8>
        1327:    b8 00 00 00 00           mov    $0x0,%eax
        132c:    e8 3f fd ff ff           callq  1070 */
            printf("%ld\n", j);

        /*1331:    48 8d 45 f0              lea    -0x10(%rbp),%rax
        1335:    48 89 c6                 mov    %rax,%rsi
        1338:    48 8d 3d c9 0c 00 00     lea    0xcc9(%rip),%rdi        # 2008 <_IO_stdin_used+0x8>
        133f:    b8 00 00 00 00           mov    $0x0,%eax
        1344:    e8 27 fd ff ff           callq  1070 */
            printf("%lx\n", (long)&j);

        /*1349:    48 8b 45 f0              mov    -0x10(%rbp),%rax
        134d:    48 8d 70 14              lea    0x14(%rax),%rsi
        1351:    48 8b 45 f0              mov    -0x10(%rbp),%rax
        1355:    4c 8d 40 10              lea    0x10(%rax),%r8
        1359:    48 8b 45 f0              mov    -0x10(%rbp),%rax
        135d:    48 8d 78 0c              lea    0xc(%rax),%rdi
        1361:    48 8b 45 f0              mov    -0x10(%rbp),%rax
        1365:    48 8d 48 08              lea    0x8(%rax),%rcx
        1369:    48 8b 45 f0              mov    -0x10(%rbp),%rax
        136d:    48 8d 50 04              lea    0x4(%rax),%rdx
        1371:    48 8b 45 f0              mov    -0x10(%rbp),%rax
        1375:    48 83 ec 08              sub    $0x8,%rsp
        1379:    56                       push   %rsi
        137a:    4d 89 c1                 mov    %r8,%r9
        137d:    49 89 f8                 mov    %rdi,%r8
        1380:    48 89 c6                 mov    %rax,%rsi
        1383:    48 8d 3d 86 0c 00 00     lea    0xc86(%rip),%rdi        # 2010 <_IO_stdin_used+0x10>
        138a:    b8 00 00 00 00           mov    $0x0,%eax
        138f:    e8 dc fc ff ff           callq  1070 */
        printf("%d %d %d %d %d %d\n", j, j+0x4, j+0x8, j+0xc, j+0x10, j+0x14);

        /*1394:    48 83 c4 10              add    $0x10,%rsp
        1398:    48 8b 45 f0              mov    -0x10(%rbp),%rax
        139c:    89 45 ec                 mov    %eax,-0x14(%rbp)
        139f:    48 8b 45 f0              mov    -0x10(%rbp),%rax
        13a3:    48 83 c0 04              add    $0x4,%rax
        13a7:    89 45 e8                 mov    %eax,-0x18(%rbp)
        13aa:    48 8b 45 f0              mov    -0x10(%rbp),%rax
        13ae:    48 83 c0 08              add    $0x8,%rax
        13b2:    89 45 e4                 mov    %eax,-0x1c(%rbp)
        13b5:    48 8b 45 f0              mov    -0x10(%rbp),%rax
        13b9:    48 83 c0 0c              add    $0xc,%rax
        13bd:    89 45 e0                 mov    %eax,-0x20(%rbp)
        13c0:    8b 75 e0                 mov    -0x20(%rbp),%esi
        13c3:    8b 4d e4                 mov    -0x1c(%rbp),%ecx
        13c6:    8b 55 e8                 mov    -0x18(%rbp),%edx
        13c9:    8b 45 ec                 mov    -0x14(%rbp),%eax
        13cc:    41 89 f0                 mov    %esi,%r8d
        13cf:    89 c6                    mov    %eax,%esi
        13d1:    48 8d 3d 57 0c 00 00     lea    0xc57(%rip),%rdi        # 202f <_IO_stdin_used+0x2f>
        13d8:    b8 00 00 00 00           mov    $0x0,%eax
        13dd:    e8 8e fc ff ff           callq  1070 */

        a[0] = j;
        a[1] = j + 4;
        a[2] = j + 8;
        a[3] = j + 0xc;
        printf("%d %d %d %d\n", a[0], a[1], a[2], a[3]);
        
        /*13e2:    90                       nop
        13e3:    48 8b 45 f8              mov    -0x8(%rbp),%rax
        13e7:    64 48 33 04 25 28 00     xor    %fs:0x28,%rax
        13ee:    00 00
        13f0:    74 05                    je     13f7
        13f2:    e8 69 fc ff ff           callq  1060 <__stack_chk_fail@plt>
        13f7:    c9                       leaveq
        13f8:    c3                       retq   */
    }

    void a_3()
    {
        /*13f9:    f3 0f 1e fa              endbr64
        13fd:    55                       push   %rbp
        13fe:    48 89 e5                 mov    %rsp,%rbp
        1401:    48 83 ec 20              sub    $0x20,%rsp
        1405:    64 48 8b 04 25 28 00     mov    %fs:0x28,%rax
        140c:    00 00
        140e:    48 89 45 f8              mov    %rax,-0x8(%rbp)
        1412:    31 c0                    xor    %eax,%eax
        1414:    48 c7 45 f0 03 00 00     movq   $0x3,-0x10(%rbp) */
            long j = 0x3;

        /*141b:    00
        141c:    c7 45 e0 00 00 00 00     movl   $0x0,-0x20(%rbp)
        1423:    8b 45 e0                 mov    -0x20(%rbp),%eax
        1426:    89 45 e4                 mov    %eax,-0x1c(%rbp)
        1429:    8b 45 e4                 mov    -0x1c(%rbp),%eax
        142c:    89 45 e8                 mov    %eax,-0x18(%rbp)
        142f:    8b 45 e8                 mov    -0x18(%rbp),%eax
        1432:    89 45 ec                 mov    %eax,-0x14(%rbp)*/
            int a[4] ;
            a[0] = a[1] = a[2] = a[3] = 0;

        /*1435:    48 8b 45 f0              mov    -0x10(%rbp),%rax
        1439:    48 89 c6                 mov    %rax,%rsi
        143c:    48 8d 3d c5 0b 00 00     lea    0xbc5(%rip),%rdi        # 2008 <_IO_stdin_used+0x8>
        1443:    b8 00 00 00 00           mov    $0x0,%eax
        1448:    e8 23 fc ff ff           callq  1070 */
            printf("%ld\n", j);

        /*144d:    48 8d 45 f0              lea    -0x10(%rbp),%rax
        1451:    48 89 c6                 mov    %rax,%rsi
        1454:    48 8d 3d ad 0b 00 00     lea    0xbad(%rip),%rdi        # 2008 <_IO_stdin_used+0x8>
        145b:    b8 00 00 00 00           mov    $0x0,%eax
        1460:    e8 0b fc ff ff           callq  1070 */
            printf("%lx\n", &j);

        /*1465:    48 8b 45 f0              mov    -0x10(%rbp),%rax
        1469:    48 8d 70 14              lea    0x14(%rax),%rsi
        146d:    48 8b 45 f0              mov    -0x10(%rbp),%rax
        1471:    4c 8d 40 10              lea    0x10(%rax),%r8
        1475:    48 8b 45 f0              mov    -0x10(%rbp),%rax
        1479:    48 8d 78 0c              lea    0xc(%rax),%rdi
        147d:    48 8b 45 f0              mov    -0x10(%rbp),%rax
        1481:    48 8d 48 08              lea    0x8(%rax),%rcx
        1485:    48 8b 45 f0              mov    -0x10(%rbp),%rax
        1489:    48 8d 50 04              lea    0x4(%rax),%rdx
        148d:    48 8b 45 f0              mov    -0x10(%rbp),%rax
        1491:    48 83 ec 08              sub    $0x8,%rsp
        1495:    56                       push   %rsi
        1496:    4d 89 c1                 mov    %r8,%r9
        1499:    49 89 f8                 mov    %rdi,%r8
        149c:    48 89 c6                 mov    %rax,%rsi
        149f:    48 8d 3d 6a 0b 00 00     lea    0xb6a(%rip),%rdi        # 2010 <_IO_stdin_used+0x10>
        14a6:    b8 00 00 00 00           mov    $0x0,%eax
        14ab:    e8 c0 fb ff ff           callq  1070 */
            printf("%d %d %d %d %d %d\n", j, j+0x4, j+0x8, j+0xc, j+0x10, j+0x14);

        /*14b0:    48 83 c4 10              add    $0x10,%rsp
        14b4:    48 8b 45 f0              mov    -0x10(%rbp),%rax
        14b8:    89 45 ec                 mov    %eax,-0x14(%rbp)
        14bb:    48 8b 45 f0              mov    -0x10(%rbp),%rax
        14bf:    48 83 c0 04              add    $0x4,%rax
        14c3:    89 45 e8                 mov    %eax,-0x18(%rbp)
        14c6:    48 8b 45 f0              mov    -0x10(%rbp),%rax
        14ca:    48 83 c0 08              add    $0x8,%rax
        14ce:    89 45 e4                 mov    %eax,-0x1c(%rbp)
        14d1:    48 8b 45 f0              mov    -0x10(%rbp),%rax
        14d5:    48 83 c0 0c              add    $0xc,%rax
        14d9:    89 45 e0                 mov    %eax,-0x20(%rbp)
        14dc:    8b 75 e0                 mov    -0x20(%rbp),%esi
        14df:    8b 4d e4                 mov    -0x1c(%rbp),%ecx
        14e2:    8b 55 e8                 mov    -0x18(%rbp),%edx
        14e5:    8b 45 ec                 mov    -0x14(%rbp),%eax
        14e8:    41 89 f0                 mov    %esi,%r8d
        14eb:    89 c6                    mov    %eax,%esi
        14ed:    48 8d 3d 3b 0b 00 00     lea    0xb3b(%rip),%rdi        # 202f <_IO_stdin_used+0x2f>
        14f4:    b8 00 00 00 00           mov    $0x0,%eax
        14f9:    e8 72 fb ff ff           callq  1070 */
            a[0] = j;
            a[1] = j + 4;
            a[2] = j + 8;
            a[3] = j + 0xc;
            printf("%d %d %d %d\n", a[0], a[1], a[2], a[3]);

        /*14fe:    90                       nop
        14ff:    48 8b 45 f8              mov    -0x8(%rbp),%rax
        1503:    64 48 33 04 25 28 00     xor    %fs:0x28,%rax
        150a:    00 00
        150c:    74 05                    je     1513
        150e:    e8 4d fb ff ff           callq  1060 <__stack_chk_fail@plt>
        1513:    c9                       leaveq
        1514:    c3                       retq   */
    }

    int main()
    {
        /*1515:    f3 0f 1e fa              endbr64
        1519:    55                       push   %rbp
        151a:    48 89 e5                 mov    %rsp,%rbp
        151d:    b8 00 00 00 00           mov    $0x0,%eax
        1522:    e8 42 fc ff ff           callq  1169 */
            a_1();

        /*1527:    b8 00 00 00 00           mov    $0x0,%eax
        152c:    e8 ac fd ff ff           callq  12dd */
            a_0();

        /*1531:    b8 00 00 00 00           mov    $0x0,%eax
        1536:    e8 be fe ff ff           callq  13f9 */
            a_3();

        /*153b:    90                       nop
        153c:    5d                       pop    %rbp
        153d:    c3                       retq   
        153e:    66 90                    xchg   %ax,%ax*/
        return 0;
    }

    // code
    void a_1()
    {
        int *a = 1;
        int byte1, byte2, byte3, byte4;
        int b = 2;

        byte1 = byte2 = byte3 = byte4 = 0;

        printf("a=%x\n", a);    // 1
        printf("a=%x\n", &a);    // b7d24708

        printf("0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", &a[0], &a[1], &a[2], &a[3], &a[4], &a[5]); // 0x1 0x5 0x9 0xd 0x11 0x15
        //printf("%x %x %x %x\n", a[0], a[1], a[2], a[3]);     // Segmentation fault (core dumped)

        byte1 = (char *)&a[0];
        byte2 = (char *)&a[1];
        byte3 = (char *)&a[2];
        byte4 = (char *)&a[3];

        printf("%x %x %x %x\n", byte1, byte2, byte3, byte4); // 1 5 9 d

        a = &b;
        printf("b=%x\n", &b);    // b7d246f4
        printf("a=%x\n", a);    // b7d246f4
        printf("a=%x\n", *a);    // 2
    }

    void a_0()
    {
        int *a = 0;
        int byte1, byte2, byte3, byte4;

        byte1 = byte2 = byte3 = byte4 = 0;

        printf("a=%x\n", a);    // 0    指向地址0
        //printf("a=%d\n", *a);    // Segmentation fault (core dumped) 取地址0上的数据,报错
        printf("a=%x\n", &a);    // c03f1498

        printf("0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", &a[0], &a[1], &a[2], &a[3], &a[4], &a[5]); // 0x0 0x4 0x8 0xc 0x10 0x14
        //printf("%x %x %x %x\n", a[0], a[1], a[2], a[3]);     // Segmentation fault (core dumped)

        byte1 = (char *)&a[0];
        byte2 = (char *)&a[1];
        byte3 = (char *)&a[2];
        byte4 = (char *)&a[3];

        printf("%x %x %x %x\n", byte1, byte2, byte3, byte4); // 0 4 8 c
    }

    void a_3()
    {
        int *a = 3;
        int byte1, byte2, byte3, byte4;

        byte1 = byte2 = byte3 = byte4 = 0;

        printf("a=%x\n", a);    // 3
        printf("a=%x\n", &a);    // ce340a48

        printf("0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", &a[0], &a[1], &a[2], &a[3], &a[4], &a[5]); // 0x3 0x7 0xb 0xf 0x13 0x17
        //printf("%x %x %x %x\n", a[0], a[1], a[2], a[3]);     // Segmentation fault (core dumped)

        byte1 = (char *)&a[0];
        byte2 = (char *)&a[1];
        byte3 = (char *)&a[2];
        byte4 = (char *)&a[3];

        printf("%x %x %x %x\n", byte1, byte2, byte3, byte4); // 3 7 b f
    }

    void main()
    {
        a_1();
        a_0();
        a_3();
    }

  • 相关阅读:
    动漫制作技巧如何制作动漫视频
    jupyter 挂掉的内核和transform=torchvision.transforms.ToTensor()
    初识Nacos
    如何使用记事本制作一个简陋的小网页(1)
    电脑屏幕模糊?这5个方法教你恢复清晰屏幕!
    OpenGL 函数列表
    《六月集训》(第二十二天)——有序集合
    Nature子刊:一个从大脑结构中识别阿尔茨海默病维度表征的深度学习框架
    自动驾驶的法律和伦理问题
    MAX/MSP SDK学习04:Messages selector的使用
  • 原文地址:https://blog.csdn.net/xiaozhiwise/article/details/128112437