一、2-9-9-12分页结构

PDPTE,PDE,PTE都占8字节。

二、页目录指针表项 Page-Directory-Point-Table Entry

PDPTE的12-35位存储了页目录表基址的高24位,低12位补零。物理地址共占36位,接下来介绍的PDE,PTE均是如此。

PCD, PWT等属性等学到TLB才知道是干嘛的。

三、页目录项 PDE

从上图可以看出,PS位=1时,PDE直接指向大物理页,其中,物理页偏移由线性地址的剩余21位(32-2-9=21)构成,由此推出大物理页占2^21=2MB;PS=0时,PDE指向页表。

解释一下G位,G=1表示这是全局页,是多个进程共享的,这种页是通过 CreateFileMapping 申请的。与之对应的,G=0就是进程独享的物理页,这种页是通过 VirtualAlloc 分配的。

G=1,即为全局页,进程(CR3)切换时,TLB中的记录不会被刷新。

最后解释一下最高位(图中没有标出的保留位),称为XD位或者NX位,当最高位置1,表示这个物理页不能当成代码执行。XD位是PDE和PTE都有的,PDE或PTE的XD位只要有一个是1,这个物理页就不能执行。

四、页表项 PTE

属性部分和10-10-12差不多,没什么新东西,注意物理页基址是36位,最高位是XD位即可。

五、给0线性地址挂上物理页

写一个测试程序:

// ReadWriteNULL_2-9-9-12.cpp : Defines the entry point for the console application.
//#include "stdafx.h"int _tmain(int argc, _TCHAR* argv[])
{char data[0x1000] = {0};int *p = NULL;printf("可用的物理页基址:%p\n", data);printf("请在windbg中给NULL挂物理页.\n");getchar(); // windbg...// 读写NULL*p = 0x20201008;printf("*NULL = %x\n", *p);getchar();return 0;
}

让程序跑起来:

上节课已经手动拆过线性地址啦,所以今天就用 !vtop 偷懒了。

查CR3

!process 0 0
CR3=134c03e0

拆NULL

kd> !vtop 134c03e0 0
X86VtoP: Virt 00000000, pagedir 134c03e0
X86VtoP: PAE PDPE 134c03e0 - 0000000011046001
X86VtoP: PAE PDE 11046000 - 000000000f4e1067
X86VtoP: PAE PTE f4e1000 - 0000000000000000
X86VtoP: PAE zero PTE
Virtual address 0 translation fails, error 0xD0000147.

拆0x12ef60

kd> !vtop 134c03e0 12ef60
X86VtoP: Virt 0012ef60, pagedir 134c03e0
X86VtoP: PAE PDPE 134c03e0 - 0000000011046001
X86VtoP: PAE PDE 11046000 - 000000000f4e1067
X86VtoP: PAE PTE f4e1970 - 800000001d6b5067
X86VtoP: PAE Mapped phys 1d6b5f60
Virtual address 12ef60 translates to physical address 1d6b5f60.

挂物理页(没有!eq指令??)

!ed f4e1000 1d6b5067
!ed f4e1004 80000000

改好了,执行剩余代码:

实验成功。

六、修改页属性,实现应用层读写高2G内存地址

编写一个程序,读写0x8003f048.

// ReadWriteH2G_2-9-9-12.cpp : Defines the entry point for the console application.
//#include "stdafx.h"
#include <windows.h>int _tmain(int argc, _TCHAR* argv[])
{printf("请在windbg修改8003f048的U/S位.\n");getchar();printf("%08x\n", *(PDWORD)0x8003f048); // 读*(PDWORD)0x8003f048 = 0x12345678; // 写printf("%08x\n", *(PDWORD)0x8003f048); // 读getchar();return 0;
}

让程序跑起来。

查CR3

!process 0 0
CR3 = 12100420

拆8003f048

!vtop 12100420 8003f048
kd> !vtop 12100420 8003f048
X86VtoP: Virt 8003f048, pagedir 12100420
X86VtoP: PAE PDPE 12100430 - 00000000044c8001
X86VtoP: PAE PDE 44c8000 - 0000000000b5a163
X86VtoP: PAE PTE b5a1f8 - 000000000003f163
X86VtoP: PAE Mapped phys 3f048
Virtual address 8003f048 translates to physical address 3f048.

改U/S位,和PTE的G位
G=1时,程序会崩,只有G=0才能成功。
简单解释一下G位:
PDE中,只有PS=1(大页)时,G才有效。
G位是全局页的意思,G=1时,这个线性地址对应的页是全局页,进程切换时,对应的TLB不会改变。多个进程的高2G数据大部分都是相同的,我们不希望在切换进程时对这部分TLB做多余的刷新,所以需要设置G=1以提高效率。

回到本文,我们已经知道PDE的PS=0,所以我们不用管PDE的G。关键是PTE的G,为什么要改成0呢?因为线性地址 0x8003f048 默认是G=1,它在CPU中有TLB缓存。

我们修改了 0x8003f048 的PTE的U/S位,但是因为G=1,在CPU中有缓存,访问线性地址时优先读取TLB缓存,而缓存中的ATTR并没有改变,所以我们对U/S的修改是无效的。即使用 !ed 指令改了U/S,我们的应用层代码试图访问 0x8003f048 时,用的仍然是旧的属性,U/S仍然是0.

更多关于TLB和G位的知识,请看后续的TLB专题博客。

!ed 44c8000 00b5a167
!ed b5a1f8 0003f067

执行剩余的代码:

七、逆向分析MmIsAddressValid函数

首先给出我自己画的示意图:

根据示意图,0xC000000是第一张页表的线性地址,0xC0600000是第一张页目录表的线性地址。

结合示意图,理解下面的公式:

2-9-9-12
PDPTI-PDI-PTI-OFFSET                    公式:
pPDE = 0xc0600000 + (PDPTI*4KB) + (PDI*8)
pPTE = 0xc0000000 + (PDPTI*2MB) + (PDI*4KB) + (PTI*8)                   更高效的公式(MmIsAddressValid是这么干的)
pPDE = 0xc0600000 + ((addr >> 18) & 0x3ff8)
pPTE = 0xc0000000 + ((addr >> 9) & 0x7ffff8)

解释:
0xc0600000 是第一张页目录表,0xc0600000 + (PDPTI * 4KB) 就是找线性地址对应的页目录表,再加上(PDI * 8)就找到了对应的PDE。

0xc0000000 是第一张页表,0xc0000000 + (PDPTI * 2MB) 就是找线性地址对应的2MB页表的基址,然后加上 (PDI4KB) 就是对应的页表,最后再加上(PTI8)就找到了PTE。

理解了2-9-9-12的映射结构,再来分析 MmIsAddressValid 函数就比较容易了。
该函数为了提高效率,移位看起来比较费脑,但只要理解了我上面画的示意图和那些公式,分析起来应该就没什么问题了。

代码中有一些莫名其妙的语句,比如:

.text:004399A1                 mov     [ebp+var_4], eax.text:004399B7                 push    0
.text:004399B9                 mov     [ebp+var_8], edx
.text:004399BC                 pop     eax

猜测是因为编程使用的是C语言,所以生成了一些冗余的代码。

分析前:

 ---------------------------------------------------------------------------
.text:0043997A                 align 10h
.text:00439980 ; Exported entry 685. MmIsAddressValid
.text:00439980
.text:00439980 ; =============== S U B R O U T I N E =======================================
.text:00439980
.text:00439980 ; Attributes: bp-based frame
.text:00439980
.text:00439980 ; BOOLEAN __stdcall MmIsAddressValid(PVOID VirtualAddress)
.text:00439980                 public _MmIsAddressValid@4
.text:00439980 _MmIsAddressValid@4 proc near           ; CODE XREF: IopIsAddressRangeValid(x,x)+2Fp
.text:00439980                                         ; IopGetMaxValidMemorySize(x,x)+29p ...
.text:00439980
.text:00439980 var_8           = dword ptr -8
.text:00439980 var_4           = dword ptr -4
.text:00439980 VirtualAddress  = dword ptr  8
.text:00439980
.text:00439980                 mov     edi, edi
.text:00439982                 push    ebp
.text:00439983                 mov     ebp, esp
.text:00439985                 push    ecx
.text:00439986                 push    ecx
.text:00439987                 mov     ecx, [ebp+VirtualAddress]
.text:0043998A                 push    esi
.text:0043998B                 mov     eax, ecx
.text:0043998D                 shr     eax, 12h
.text:00439990                 mov     esi, 3FF8h
.text:00439995                 and     eax, esi
.text:00439997                 sub     eax, 3FA00000h
.text:0043999C                 mov     edx, [eax]
.text:0043999E                 mov     eax, [eax+4]
.text:004399A1                 mov     [ebp+var_4], eax
.text:004399A4                 mov     eax, edx
.text:004399A6                 push    edi
.text:004399A7                 and     eax, 1
.text:004399AA                 xor     edi, edi
.text:004399AC                 or      eax, edi
.text:004399AE                 jz      short loc_439A11
.text:004399B0                 mov     edi, 80h
.text:004399B5                 and     edx, edi
.text:004399B7                 push    0
.text:004399B9                 mov     [ebp+var_8], edx
.text:004399BC                 pop     eax
.text:004399BD                 jz      short loc_4399C3
.text:004399BF                 test    eax, eax
.text:004399C1                 jz      short loc_439A15
.text:004399C3
.text:004399C3 loc_4399C3:                             ; CODE XREF: MmIsAddressValid(x)+3Dj
.text:004399C3                 shr     ecx, 9
.text:004399C6                 and     ecx, 7FFFF8h
.text:004399CC                 mov     eax, [ecx-3FFFFFFCh]
.text:004399D2                 sub     ecx, 40000000h
.text:004399D8                 mov     edx, [ecx]
.text:004399DA                 mov     [ebp+var_4], eax
.text:004399DD                 push    ebx
.text:004399DE                 mov     eax, edx
.text:004399E0                 xor     ebx, ebx
.text:004399E2                 and     eax, 1
.text:004399E5                 or      eax, ebx
.text:004399E7                 pop     ebx
.text:004399E8                 jz      short loc_439A11
.text:004399EA                 and     edx, edi
.text:004399EC                 push    0
.text:004399EE                 mov     [ebp+var_8], edx
.text:004399F1                 pop     eax
.text:004399F2                 jz      short loc_439A15
.text:004399F4                 test    eax, eax
.text:004399F6                 jnz     short loc_439A15
.text:004399F8                 and     ecx, esi
.text:004399FA                 mov     ecx, [ecx-3FA00000h]
.text:00439A00                 mov     eax, 81h
.text:00439A05                 and     ecx, eax
.text:00439A07                 xor     edx, edx
.text:00439A09                 cmp     ecx, eax
.text:00439A0B                 jnz     short loc_439A15
.text:00439A0D                 test    edx, edx
.text:00439A0F                 jnz     short loc_439A15
.text:00439A11
.text:00439A11 loc_439A11:                             ; CODE XREF: MmIsAddressValid(x)+2Ej
.text:00439A11                                         ; MmIsAddressValid(x)+68j
.text:00439A11                 xor     al, al
.text:00439A13                 jmp     short loc_439A17
.text:00439A15 ; ---------------------------------------------------------------------------
.text:00439A15
.text:00439A15 loc_439A15:                             ; CODE XREF: MmIsAddressValid(x)+41j
.text:00439A15                                         ; MmIsAddressValid(x)+72j ...
.text:00439A15                 mov     al, 1
.text:00439A17
.text:00439A17 loc_439A17:                             ; CODE XREF: MmIsAddressValid(x)+93j
.text:00439A17                 pop     edi
.text:00439A18                 pop     esi
.text:00439A19                 leave
.text:00439A1A                 retn    4
.text:00439A1A _MmIsAddressValid@4 endp

分析后:
主要是判断PDE PTE的P,PS位。

 ---------------------------------------------------------------------------
.text:0043997A                 align 10h
.text:00439980 ; Exported entry 685. MmIsAddressValid
.text:00439980
.text:00439980 ; =============== S U B R O U T I N E =======================================
.text:00439980
.text:00439980 ; Attributes: bp-based frame
.text:00439980
.text:00439980 ; BOOLEAN __stdcall MmIsAddressValid(PVOID VirtualAddress)
.text:00439980                 public _MmIsAddressValid@4
.text:00439980 _MmIsAddressValid@4 proc near           ; CODE XREF: IopIsAddressRangeValid(x,x)+2Fp
.text:00439980                                         ; IopGetMaxValidMemorySize(x,x)+29p ...
.text:00439980
.text:00439980 var_8           = dword ptr -8
.text:00439980 var_4           = dword ptr -4
.text:00439980 VirtualAddress  = dword ptr  8
.text:00439980
.text:00439980                 mov     edi, edi
.text:00439982                 push    ebp
.text:00439983                 mov     ebp, esp
.text:00439985                 push    ecx
.text:00439986                 push    ecx
.text:00439987                 mov     ecx, [ebp+VirtualAddress] ; ecx = VAddr
.text:0043998A                 push    esi
.text:0043998B                 mov     eax, ecx        ; eax = VAddr
.text:0043998D                 shr     eax, 12h        ; VAddr >> 18
.text:00439990                 mov     esi, 3FF8h
.text:00439995                 and     eax, esi        ; eax = PDPTI * 4KB + PDI * 8
.text:00439997                 sub     eax, 3FA00000h  ; eax = C0600000 + PDPTI * 4KB + PDI * 8
.text:00439997                                         ; eax 指向了 PDE
.text:0043999C                 mov     edx, [eax]
.text:0043999E                 mov     eax, [eax+4]    ; eax,edx = PDE
.text:004399A1                 mov     [ebp+var_4], eax
.text:004399A4                 mov     eax, edx        ; eax = PDE低4字节
.text:004399A6                 push    edi
.text:004399A7                 and     eax, 1          ; 取PDE的P位
.text:004399AA                 xor     edi, edi
.text:004399AC                 or      eax, edi        ; if (P==0) 返回假
.text:004399AE                 jz      short loc_439A11
.text:004399B0                 mov     edi, 80h
.text:004399B5                 and     edx, edi        ; 取PS位判断
.text:004399B7                 push    0
.text:004399B9                 mov     [ebp+var_8], edx
.text:004399BC                 pop     eax             ; eax = 0
.text:004399BD                 jz      short loc_4399C3 ; if (PS==0) 跳转到小页处理
.text:004399BF                 test    eax, eax
.text:004399C1                 jz      short loc_439A15 ; 如果PS==1,即大页,就直接返回真
.text:004399C3
.text:004399C3 loc_4399C3:                             ; CODE XREF: MmIsAddressValid(x)+3Dj
.text:004399C3                 shr     ecx, 9          ; VAddr >> 9  效果相当于右移12位,然后乘以8
.text:004399C6                 and     ecx, 7FFFF8h    ; ecx = PDPTI * 2MB + PDI * 4KB + PTI * 8
.text:004399CC                 mov     eax, [ecx-3FFFFFFCh]
.text:004399D2                 sub     ecx, 40000000h  ; ecx = C0000000 + PDPTI * 2MB + PDI * 4KB + PTI * 8
.text:004399D2                                         ; ecx 指向 PTE
.text:004399D8                 mov     edx, [ecx]      ; edx = PTE低4字节
.text:004399DA                 mov     [ebp+var_4], eax
.text:004399DD                 push    ebx
.text:004399DE                 mov     eax, edx        ; eax = PTE低4字节
.text:004399E0                 xor     ebx, ebx        ; ebx = 0
.text:004399E2                 and     eax, 1          ; 取PTE的P位
.text:004399E5                 or      eax, ebx
.text:004399E7                 pop     ebx
.text:004399E8                 jz      short loc_439A11 ; P==0 返回假
.text:004399EA                 and     edx, edi        ; PTE低4字节 & 80h,即取PAT位
.text:004399EC                 push    0
.text:004399EE                 mov     [ebp+var_8], edx
.text:004399F1                 pop     eax
.text:004399F2                 jz      short loc_439A15 ; PAT==0 返回真
.text:004399F4                 test    eax, eax
.text:004399F6                 jnz     short loc_439A15
.text:004399F8                 and     ecx, esi        ; 后面是判断PAT==1的情况,我就不分析了,看不懂
.text:004399FA                 mov     ecx, [ecx-3FA00000h]
.text:00439A00                 mov     eax, 81h
.text:00439A05                 and     ecx, eax
.text:00439A07                 xor     edx, edx
.text:00439A09                 cmp     ecx, eax
.text:00439A0B                 jnz     short loc_439A15
.text:00439A0D                 test    edx, edx
.text:00439A0F                 jnz     short loc_439A15
.text:00439A11
.text:00439A11 loc_439A11:                             ; CODE XREF: MmIsAddressValid(x)+2Ej
.text:00439A11                                         ; MmIsAddressValid(x)+68j
.text:00439A11                 xor     al, al
.text:00439A13                 jmp     short loc_439A17
.text:00439A15 ; ---------------------------------------------------------------------------
.text:00439A15
.text:00439A15 loc_439A15:                             ; CODE XREF: MmIsAddressValid(x)+41j
.text:00439A15                                         ; MmIsAddressValid(x)+72j ...
.text:00439A15                 mov     al, 1
.text:00439A17
.text:00439A17 loc_439A17:                             ; CODE XREF: MmIsAddressValid(x)+93j
.text:00439A17                 pop     edi
.text:00439A18                 pop     esi
.text:00439A19                 leave
.text:00439A1A                 retn    4
.text:00439A1A _MmIsAddressValid@4 endp

八、编写代码实现修改页属性,实现应用层读写高2G内存地址

2-9-9-12
PDPTI-PDI-PTI-OFFSET                    公式:
pPDE = 0xc0600000 + (PDPTI*4KB) + (PDI*8)
pPTE = 0xc0000000 + (PDPTI*2MB) + (PDI*4KB) + (PTI*8)                   更高效的公式(MmIsAddressValid是这么干的)
pPDE = 0xc0600000 + ((addr >> 18) & 0x3ff8)
pPTE = 0xc0000000 + ((addr >> 9) & 0x7ffff8)
// ReadWriteH2G_2-9-9-12.cpp : Defines the entry point for the console application.
//#include "stdafx.h"
#include <windows.h>//2-9-9-12
//PDPTI-PDI-PTI-OFFSETDWORD *GetPDE(DWORD addr)
{//return (DWORD *)(0xc0600000 + ((addr >> 18) & 0x3ff8));DWORD PDPTI = addr >> 30;DWORD PDI = (addr >> 21) & 0x000001FF;DWORD PTI = (addr >> 12) & 0x000001FF;return (DWORD *)(0xC0600000 + PDPTI * 0x1000 + PDI * 8);
}DWORD *GetPTE(DWORD addr)
{//return (DWORD *)(0xc0000000 + ((addr >> 9) & 0x7ffff8));DWORD PDPTI = addr >> 30;DWORD PDI = (addr >> 21) & 0x000001FF;DWORD PTI = (addr >> 12) & 0x000001FF;return (DWORD *)(0xC0000000 + PDPTI * 0x200000 + PDI * 0x1000 + PTI * 8);
}void __declspec(naked) R0Function()
{__asm{push ebpmov ebp,espsub esp,0x1000pushadpushfd        }__asm push fs//__asm int 3// 修改8003f048的U/S位*GetPDE(0x8003f048) |= 0x00000004;*GetPTE(0x8003f048) |= 0x00000004;// 修改PTE的G位*GetPTE(0x8003f048) &= 0xFFFFFEFF;//__asm int 3__asm pop fs__asm{popfdpopadadd esp,0x1000mov esp,ebppop ebpiretd}
}int _tmain(int argc, _TCHAR* argv[])
{printf("在IDT表构建中断门,请在windbg中执行下面的指令:\n");printf("eq 8003f500 %04xee00`0008%04x\n",(DWORD)R0Function>>16,(DWORD)R0Function & 0x0000FFFF);getchar();__asm int 0x20printf("0x8003f048 U/S,G位修改成功.\n");printf("*(PDWORD)0x8003f048 = %08x\n", *(PDWORD)0x8003f048); // 读*(PDWORD)0x8003f048 = 0x12345678; // 写printf("*(PDWORD)0x8003f048 = %08x\n", *(PDWORD)0x8003f048); // 读getchar();return 0;
}

九、测试XD位

我写了一个程序,是用一个指针指向一块内存,然后用汇编call过去。然后可以对比XD=0和XD=1时,CALL的结果。

// TestXD.cpp : Defines the entry point for the console application.
//#include "stdafx.h"
#include <Windows.h>char *buff;DWORD *GetPDE(DWORD addr)
{//return (DWORD *)(0xc0600000 + ((addr >> 18) & 0x3ff8));DWORD PDPTI = addr >> 30;DWORD PDI = (addr >> 21) & 0x000001FF;DWORD PTI = (addr >> 12) & 0x000001FF;return (DWORD *)(0xC0600000 + PDPTI * 0x1000 + PDI * 8);
}DWORD *GetPTE(DWORD addr)
{//return (DWORD *)(0xc0000000 + ((addr >> 9) & 0x7ffff8));DWORD PDPTI = addr >> 30;DWORD PDI = (addr >> 21) & 0x000001FF;DWORD PTI = (addr >> 12) & 0x000001FF;return (DWORD *)(0xC0000000 + PDPTI * 0x200000 + PDI * 0x1000 + PTI * 8);
}void __declspec(naked) R0Function()
{__asm{push ebpmov ebp,espsub esp,0x1000pushadpushfd        }__asm push fs//__asm int 3// 修改buff的XD位*(GetPDE((DWORD)buff) + 1) |= 0x80000000;*(GetPTE((DWORD)buff) + 1) |= 0x80000000;//__asm int 3__asm pop fs__asm{popfdpopadadd esp,0x1000mov esp,ebppop ebpiretd}
}int _tmain(int argc, _TCHAR* argv[])
{// 申请一个内存页,写入硬编码    buff = (char *)VirtualAlloc(NULL,0x1000,MEM_COMMIT,PAGE_EXECUTE_READWRITE);printf("buff: %p\n", buff);BYTE bytecode [7] = {0x90,0xB8,0x01,0x00,0x00,0x00,0xC3}; // NOP, MOV EAX,1, RETmemcpy(buff,bytecode,7);// 测试,对比XD=0和XD=1的运行结果printf("输入XD位:");int xd;scanf("%d",&xd); // 输入0可以调用,输入1调用失败getchar();if (xd == 1){printf("在IDT表构建中断门,请在windbg中执行下面的指令:\n");printf("eq 8003f500 %04xee00`0008%04x\n",(DWORD)R0Function>>16,(DWORD)R0Function & 0x0000FFFF);getchar();__asm int 0x20printf("XD位修改成功,buff不可执行.\n");}DWORD dwEAX = 0;__asm{push eaxxor eax,eaxcall buffmov dwEAX,eaxpop eax};if (dwEAX == 0) printf("调用失败.\n");else if (dwEAX == 1) printf("调用成功.\n");printf("bye!\n");getchar();return 0;
}

如果XD=0,就是默认情况了,可以正常调用函数并返回。

如果将XD修改为1,那么执行CALL会失败,程序会卡死。

(25)2-9-9-12分页(下)相关推荐

  1. redis 系列25 哨兵Sentinel (高可用演示 下)

    原文:redis 系列25 哨兵Sentinel (高可用演示 下) 一. Sentinel 高可用环境准备 1.1 Sentinel 集群环境 环境 说明 操作系统版本 CentOS  7.4.17 ...

  2. linux telnet localhost 25,telnet localhost 25 没反应. 大家帮忙看下什么问题...

    telnet localhost 25 没反应. 大家帮忙看下什么问题... (2012-01-10 05:46:33) 标签: localhost 杂谈 telnet localhost 25 没反 ...

  3. Ubuntu 12.04 下编译Android 4.0.3

    在Ubuntu 12.04 下编译了Android 4.0.3发现了一大堆错误,网上找了一堆的更改源码啊,Android.mk的解决方法,虽然可以编译成功,但都有点坑爹的成分,为了不误人子弟就分享出来 ...

  4. android studio3.12,Android Studio V3.12环境下TV开发教程(六)提供卡片视图

    Android Studio V3.12环境下TV开发教程 文章源自:光谷佳武 https://blog.csdn.net/jiawuhan/article/details/80619656 在上一课 ...

  5. Ubuntu 12.04下安装Oracle Express 11gR2

    Ubuntu 12.04下安装Oracle Express 11gR2 [我的笔记] 参考1:http://www.linuxidc.com/Linux/2012-09/71382.htm 参考2:h ...

  6. linux ubuntu 12.04 下默认是安装了openjdk的

    ubuntu 12.04 下默认是安装了openjdk的,不过这个jdk问题比较多,因为你甚至无法启动Eclipse,所以还是需要自己安装jdk的. 1.下载jdk6 jdk6下载地址为:http:/ ...

  7. Ubuntu 12.04下搭建Web服务器 (MySQL+PHP+Apache)(转)

    看了网上很多关于用linux操作系统搭建网站服务器的教程,于是我自己也测试了很多,但今天所测试的 Ubuntu 12.04下搭建Web网站服务器 (MySQL+PHP+Apache环境),感觉这个适合 ...

  8. 通过pyenv在Mac OS X 10.12.3下安装Python-3.6.0及“*** [install] Error 1”错误的解决方法

    通过pyenv在Mac OS X 10.12.3下安装Python-3.6.0及"*** [install] Error 1"错误的解决方法 参考文章: (1)通过pyenv在Ma ...

  9. mysql webmail ubuntu12.04 imap_Ubuntu 12.04下搭建Web网站服务器 (MySQL+PHP+Apache环境)教程...

    前言 看了网上很多关于用linux操作系统搭建网站服务器的教程,于是我自己也测试了很多,但今天所测试的 Ubuntu 12.04下搭建Web网站服务器 (MySQL+PHP+Apache环境),感觉这 ...

  10. edup无线网卡驱动安装linux,EDUP EP-N8513 (RTL8188CUS芯片)在Ubuntu 12.10下的wifi不能连接问题解决方法...

    EDUP EP-N8513这款USB微型无线网卡在我刚装上的64位Ubuntu 12.10下虽然能被系统识别出来,但是并不能正常连接无线AP,具体表现为可以看到AP列表,尝试连接后不停的询问密码,即使 ...

最新文章

  1. 计算机系统的分类补充完整,数据库系统原(理B)13春A卷.doc
  2. PHP----------php封装的一些简单实用的方法汇总
  3. pandas使用replace函数将dataframe中None值以及其他异常编码值(例如,9999)替换为np.nan
  4. 智源成立面向可持续发展的人工智能智库并发布公益研究计划
  5. Qt配置GUI程序控制台输出
  6. idea加入springboot插件_带你搭一个SpringBoot+SpringData JPA的环境
  7. html5 手机拍视频滤镜,用canvas实现图片滤镜效果附演示_html5教程技巧
  8. php smarty 语法,php之Smarty根本语法和三大变量
  9. pandas遍历dataframe_chapter2-4 常用数据处理包Pandas整理4
  10. php聚合支付,pay: ThinkPHP开源聚合支付系统
  11. 在.net中使用javascript-Jint和Javascript .NET
  12. IMO Res MSC 307(88) 国际船舶材料防火试验
  13. matlab将水印图像嵌入图像,改进的图像自嵌入水印算法及其MATLAB实现
  14. 个性化茅台之中国酒韵·十大人物
  15. 一线技术人应该关注的四种思维能力
  16. Codeforces 985A. Chess Placing(1ni)(水题)(div.2)
  17. 《Java I/O》Chapter 1
  18. 政务服务一网通办建设方案(ppt)
  19. [图像]中值滤波(Matlab实现)
  20. JavaMail API 详解

热门文章

  1. mysql linux selected_MySQL的查询语句--SELECT
  2. Algorithm:机械优化设计的数学模型简介、常用优化方法、优化计算工具简介之详细攻略
  3. 成功解决This DCH driver package is not compatible with the currently installed version of Windows. This
  4. 成功解决No such file or directory: site-packages\\pyyaml-5.3-py3.6-win-amd64.egg\\EGG-INFO\\top_level.t
  5. TF之LSTM:基于Tensorflow框架采用PTB数据集建立LSTM网络的自然语言建模
  6. Py之gym:gym的简介、安装、使用方法之详细攻略
  7. Py之pyglet:Python之pyglet库的简介、安装、使用详细攻略
  8. Crawler:基于urllib库+实现爬虫有道翻译
  9. 统计学习方法第四章朴素贝叶斯法-李航
  10. Linux绝对路径和相对路径简单介绍