1. 程式人生 > >C/C++資訊隱寫術(三)之txt檔案藏入BMP檔案

C/C++資訊隱寫術(三)之txt檔案藏入BMP檔案

這一節是基於第二節的程式碼。下面是第二節的連結

這一節結束後,我們將把一個遠控程式的客戶端(潛伏者)放入BMP檔案中。

現在我們來看這一節:之txt檔案藏入BMP檔案

我們先建立一個1.txt檔案。檔案裡面儲存了資料,如下圖所示:



現在我來說明下程式的思路。

我們把這個txt檔案用二進位制的方式進行讀取,然後寫入BMP的alpha通道,就是這麼簡單的思路。

下面我們來看關鍵程式碼:

void CBMPHide::savetxtFile(char* FileName)
{
	FILE* fp = fopen(FileName, "rb");
	if (fp == NULL)
	{
		printf_s("檔案開啟失敗\n");
		return;
	}

	char buf[128];	//0xFF=255
	int n = fread(buf, 1, 128, fp);

	if (n == 0)
	{
		printf_s("檔案為空,隱藏失敗!");
		return;
	}
	fclose(fp);
	this->hideString2BMP(buf);
	this->save();
}

void CBMPHide::showtxtFile(char* szBmpFIleName/*=NULL*/)
{
	string sDstFileName = "";
	if (szBmpFIleName == 0)
	{
		sDstFileName = sBmpFileName + ".hide.bmp";
	}
	else
		sDstFileName = szBmpFIleName;

	HANDLE hfile = CreateFileA(sDstFileName.c_str(),
		GENERIC_READ | GENERIC_WRITE,
		FILE_SHARE_READ | FILE_SHARE_WRITE,
		NULL,
		OPEN_EXISTING, 0, 0);
	if (hfile == INVALID_HANDLE_VALUE)
	{
		return;
	}
	DWORD dwSize = GetFileSize(hfile, 0);
	LPBYTE pBuf1 = new byte[dwSize];

	DWORD dwRead = 0;

	ReadFile(hfile, pBuf1, dwSize, &dwRead, 0);
	CloseHandle(hfile);

	//檔案內容讀取到pBuf1中
	BITMAPFILEHEADER *pHdr = (BITMAPFILEHEADER *)pBuf1;
	LPBYTE pStr = pBuf1 + pHdr->bfOffBits + 3;
	char szTmp[1280];
	RtlZeroMemory(szTmp, 1280);
	for (int i = 0; i < 1280; i++)
	{
		if (*pStr == 0 || *pStr == 0xFF ||*pStr == 0xCC)
		{
			break;
		}
		szTmp[i] = *pStr;
		pStr += 4;
	}
	printf_s(szTmp);

	const char* filename = "from bmp.txt";
	FILE* fp = fopen(filename, "wb");
	if (fp == NULL)
	{
		printf_s("txt檔案儲存失敗!");
		return;
	}
	fwrite(szTmp, 1, strlen(szTmp) , fp);
	fclose(fp);

	delete[]pBuf1;
}
rb是以二進位制方式開啟檔案。

下面是程式原始碼打包下載:

下面是執行結果:


下面是程式的所有程式碼:

dwBmpSize.h

#define  _CRT_SECURE_NO_WARNINGS
#pragma  once
#include <string>
#include <Windows.h>
using namespace std;

class CBMPHide
{
public:
	CBMPHide();
	~CBMPHide();

	bool setBmpFileName(char* szFileName);	//設定Bmp檔名

	int getBmpWidth();	//獲取寬度
	int getBmpHeight();	//獲取高度
	int getBmpBitCount();	//獲取Bit總數
	bool save();

	bool hideString2BMP(char* szStr2Hide);	//隱藏String到BMP檔案中
	void showStringInBmp(char* szBmpFIleName=NULL);	//展示

	void savetxtFile(char* FileName);	//隱藏txt檔案到bmp影象中
	void showtxtFile(char* szBmpFIleName = NULL);	//解密出txtFile
private:
	DWORD dwBmpSize;	//圖片檔案大小
	DWORD dwTxTSize;

	string sBmpFileName;
	string sTxTFileName;

	LPBYTE pBuf;	//用於存放圖片資訊的記憶體
	LPBYTE ptxtBuf;	//用於存放txt資訊的記憶體

	BITMAPFILEHEADER* m_fileHdr;
	BITMAPINFOHEADER* m_infoHdr;
};

dwBmpSIze.cpp
#include "dwBmpSize.h"

CBMPHide::CBMPHide()
{
	sBmpFileName = "";
	pBuf = 0;
	dwBmpSize = 0;
	ptxtBuf = 0;
}

CBMPHide::~CBMPHide()
{

}

bool CBMPHide::setBmpFileName(char* szFileName)
{
	this->sBmpFileName = szFileName;
	if (pBuf)	//如果已經生成就釋放掉
	{
		delete[]pBuf;
	}

	HANDLE hfile = CreateFileA(szFileName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0);
	if (hfile == INVALID_HANDLE_VALUE)
	{
		return false;
	}

	//和struct BITMAPFILEHEADER bmfh裡面的 bfSize的大小應該是一樣的。
	dwBmpSize = GetFileSize(hfile, 0);	//獲取檔案的大小
	pBuf = new byte[dwBmpSize];
	DWORD dwRead = 0;
	ReadFile(hfile, pBuf, dwBmpSize, &dwRead, 0);
	if (dwRead != dwBmpSize)
	{
		delete[]pBuf;
		pBuf = 0;
		return false;
	}
	CloseHandle(hfile);
	m_fileHdr = (BITMAPFILEHEADER*)pBuf;
	m_infoHdr = (BITMAPINFOHEADER*)(pBuf + sizeof(BITMAPFILEHEADER));
	return true;	//成功話就是檔案的內容讀取到pBuf裡面
}


int CBMPHide::getBmpWidth()
{
	return m_infoHdr->biWidth;
}

int CBMPHide::getBmpHeight()
{
	return m_infoHdr->biHeight;
}

int CBMPHide::getBmpBitCount()
{
	return m_infoHdr->biBitCount;
}

bool CBMPHide::save()
{
	string sDstFileName = sBmpFileName + ".hide.bmp";
	HANDLE hfile = CreateFileA(sDstFileName.c_str(),
		GENERIC_READ | GENERIC_WRITE,
		FILE_SHARE_READ | FILE_SHARE_WRITE,
		NULL,
		CREATE_ALWAYS, 0, 0);
	if (hfile == INVALID_HANDLE_VALUE)
	{
		return false;
	}

	DWORD dwWritten = 0;
	WriteFile(hfile, pBuf, dwBmpSize, &dwWritten, 0);
	if (dwBmpSize != dwWritten)
	{
		return false;
	}
	CloseHandle(hfile);
	return true;
}
//隱藏一個字串到圖片中,把字串拆成位元組,寫入每個畫素的alpha通道中
bool CBMPHide::hideString2BMP(char* szStr2Hide)
{
	LPBYTE pAlpha = pBuf + m_fileHdr->bfOffBits + 3;	//第一個畫素的通道位置
	int nHide;	//成功隱藏的位元組數

	//每次迴圈寫入一個位元組,吸入alpha通道
	//(pAlpha - pBuf) < m_fileHdr->bfSize這個是判斷字串是太大,圖片不能隱藏
	for (nHide = 0; (pAlpha - pBuf) < m_fileHdr->bfSize && szStr2Hide[nHide] != 0; nHide++, pAlpha += 4)
	{
		*pAlpha = szStr2Hide[nHide];	//寫入一個位元組
	}

	return true;
}

void CBMPHide::showStringInBmp(char* szBmpFIleName/*=NULL*/)
{
	string sDstFileName="";
	if (szBmpFIleName == 0)
	{
		sDstFileName = sBmpFileName + ".hide.bmp";
	}
	else
		sDstFileName = szBmpFIleName;

	HANDLE hfile = CreateFileA(sDstFileName.c_str(),
		GENERIC_READ | GENERIC_WRITE,
		FILE_SHARE_READ | FILE_SHARE_WRITE,
		NULL,
		OPEN_EXISTING, 0, 0);
	if (hfile == INVALID_HANDLE_VALUE)
	{
		return;
	}
	DWORD dwSize = GetFileSize(hfile, 0);
	LPBYTE pBuf1 = new byte[dwSize];

	DWORD dwRead = 0;

	ReadFile(hfile, pBuf1, dwSize, &dwRead, 0);
	CloseHandle(hfile);

	//檔案內容讀取到pBuf1中
	BITMAPFILEHEADER *pHdr = (BITMAPFILEHEADER *)pBuf1;
	LPBYTE pStr = pBuf1 + pHdr->bfOffBits + 3;
	char szTmp[1280];
	RtlZeroMemory(szTmp, 1280);
	for (int i = 0; i < 1280; i++)
	{
		if (*pStr == 0 || *pStr == 0xFF)
		{
			break;
		}
		szTmp[i] = *pStr;
		pStr += 4;
	}
	printf_s(szTmp);

	delete[]pBuf1;
}

void CBMPHide::savetxtFile(char* FileName)
{
	FILE* fp = fopen(FileName, "rb");
	if (fp == NULL)
	{
		printf_s("檔案開啟失敗\n");
		return;
	}

	char buf[128];	//0xFF=255
	int n = fread(buf, 1, 128, fp);

	if (n == 0)
	{
		printf_s("檔案為空,隱藏失敗!");
		return;
	}
	fclose(fp);
	this->hideString2BMP(buf);
	this->save();
}

void CBMPHide::showtxtFile(char* szBmpFIleName/*=NULL*/)
{
	string sDstFileName = "";
	if (szBmpFIleName == 0)
	{
		sDstFileName = sBmpFileName + ".hide.bmp";
	}
	else
		sDstFileName = szBmpFIleName;

	HANDLE hfile = CreateFileA(sDstFileName.c_str(),
		GENERIC_READ | GENERIC_WRITE,
		FILE_SHARE_READ | FILE_SHARE_WRITE,
		NULL,
		OPEN_EXISTING, 0, 0);
	if (hfile == INVALID_HANDLE_VALUE)
	{
		return;
	}
	DWORD dwSize = GetFileSize(hfile, 0);
	LPBYTE pBuf1 = new byte[dwSize];

	DWORD dwRead = 0;

	ReadFile(hfile, pBuf1, dwSize, &dwRead, 0);
	CloseHandle(hfile);

	//檔案內容讀取到pBuf1中
	BITMAPFILEHEADER *pHdr = (BITMAPFILEHEADER *)pBuf1;
	LPBYTE pStr = pBuf1 + pHdr->bfOffBits + 3;
	char szTmp[1280];
	RtlZeroMemory(szTmp, 1280);
	for (int i = 0; i < 1280; i++)
	{
		if (*pStr == 0 || *pStr == 0xFF ||*pStr == 0xCC)
		{
			break;
		}
		szTmp[i] = *pStr;
		pStr += 4;
	}
	printf_s(szTmp);

	const char* filename = "from bmp.txt";
	FILE* fp = fopen(filename, "wb");
	if (fp == NULL)
	{
		printf_s("txt檔案儲存失敗!");
		return;
	}
	fwrite(szTmp, 1, strlen(szTmp) , fp);
	fclose(fp);

	delete[]pBuf1;
}

main.cpp
#include <stdio.h>
#include "dwBmpSize.h"

int main()
{
	CBMPHide hide;
	hide.setBmpFileName("test.bmp");
	printf_s("test.bmp width:%d,height:%d,bitCount%d\n",
		hide.getBmpWidth(),
		hide.getBmpHeight(),
		hide.getBmpBitCount());
	//hide.hideString2BMP("Hello Word");
	//hide.save();
	//hide.showStringInBmp("test.bmp.hide.bmp");

	hide.savetxtFile("1.txt");
	hide.showtxtFile("test.bmp.hide.bmp");
	getchar();
	return 0;
}


這一節結束後,我們將把一個遠控程式的客戶端(潛伏者)放入BMP檔案中。

相關推薦

C/C++資訊txt檔案BMP檔案

這一節是基於第二節的程式碼。下面是第二節的連結 這一節結束後,我們將把一個遠控程式的客戶端(潛伏者)放入BMP檔案中。 現在我們來看這一節:之txt檔案藏入BMP檔案 我們先建立一個1.txt檔案。檔案裡面儲存了資料,如下圖所示: 現在我來說明下程式的思路。

C#進位制轉換操作16進位制操作

一、字串和16進位制字串互轉 1.字串轉16進位制字串 /// <summary> /// 字串轉Hex,方法1使用Convert.ToString(byte, 16) /// </summary> /// <param name="s

oracle學習筆記檢查Oracle的告警日誌檔案

作為一個 DBA,或者哪怕僅僅是和 Oracle 資料庫打交道的技術人員,你都必須知道告警日誌是什麼,在何處。 而對於 DBA來說,實時的監控資料庫的告警日誌是必須進行的工作,監控並且應該根據不同的嚴重級別,傳送不同級別的告警資訊(通過郵件、簡訊) ,這可以幫助我們及時瞭解資

C++檔案操作如何統計文字的行數及如何讀取檔案某一行內容

相關文章 //如何統計文字的行數及如何讀取檔案某一行內容: #include <iostream> #include <fstream> #include <string> using namespace std

C#代碼中應用Log4NetLog4Net中配置文件的解釋

images rdquo files read 出現 插入 tof stat 日誌 <log4net> <!-- 錯誤日誌類--> <logger name="logerror"> <level value

C++: I/O流詳解——串流

name namespace 轉換 pac end 成員 col logs nbsp 一、串流 串流類是 ios 中的派生類 C++的串流對象可以連接string對象或字符串 串流提取數據時對字符串按變量類型解釋;插入數據時把類型 數據轉換成字符串 串流I/O具有格式化功能

C++學習 基本數據類型

大成 double mini png 滿足 const case bit 普通 基本數據類型 上期回顧 stdlib.h system,命令release MT導入ico文件 基本數據類型 整數 int浮點型(小數 實型) float double字符型 ch

C++標準庫STL算法

out section 區間 and include pla sort 不同 重復元素 算法頭文件: #include<algorithm> #include<numeric> 算法簡介:STL算法采用覆蓋模式而非安插模式,所以調用者必須保證有足夠

C# VS2012下的3D顯示

這樣肯定是無法編譯通過的,所以需要新增引用。 這個時候,就可以編譯執行通過。執行效果是一個黑框。   然後我們右鍵這個控制元件,進入屬性,選擇屬性(閃電按鈕)   裡面的程式碼,參照第一篇裡面,自動生成的程式碼,複

C語言面試題---指標篇

版本宣告:本文轉載於公眾號TeachPlus C語言面試題---指標篇(三) 了解了記憶體空間,接下來我們就一起看一下指標自身用法的一些題目,先來看這樣一道題目: 分析下面程式碼:` # include <stdio.h> # include

C#微信公眾號開發 -- 使用者關注之後自動回覆

通過了上一篇文章之後的微信開發者驗證之後,我們就可以做微信公眾號的程式碼開發了。 當我們點選關注某個公眾號的時候,有時候會發現他會自動給我們回覆一條訊息,比如歡迎關注XXX公眾號。這個功能其實是在點選關注的時候,使用者觸發了微信定義的事件,同時微信會返回給我們一個XML資料包,微信官方的解釋如下: 推送X

圖片利用圖片隱藏壓縮檔案

    想象一個場景,下載了一個看似普通的圖片,然後修改一下字尾名為rar再解壓就發現隱藏於其中的檔案     如何將一個壓縮檔案隱藏於圖片之中呢,先來看看圖片和壓縮檔案的結構,我們都知道檔案在計算機裡都是以二進位制的形式存在的,所以

Google C++ Style Guide中英對照

1 Naming 命名規則 The mostimportant consistency rules are those that govern naming. The style of a nameimmediately informs us what sort of th

C++ 面向物件- -運算子的過載

目錄 不同型別資料間的轉換 1、標準型別資料間的轉換 2、轉換建構函式 3、型別轉換函式 關於運算子過載的歸納   不同型別資料間的轉換 1、標準型別資料間的轉換 在以前我們對一個變數初始化或者不同資料間進行運算時,都會涉及到資料型別的轉換,只是有顯

Parasoft C/C++test 常見問題整理大全

Parasoft C/C++test幫助團隊寫出更好的程式碼,實施更有效的測試,以及持續地監視以實現質量目標。 C / C ++test可以進行靜態分析,全面程式碼審查,執行時錯誤檢測,並在單元測試和元件測試中整合覆蓋率分析。這些能夠在開發週期的開始階段,在開發桌面上自動完成。 一、C

C#事務處理Transactions事務

自.NET 2.0以來增加了System.Transactions名稱空間,為.NET應用程式帶來了一個新的事務程式設計模型。 這個名稱空間提供了幾個依賴的TransactionXXX類。Transaction是所有事務處理類的基類,並定義了所有事務類可以

C++ Primer Plus的若干收穫--

有時候懷疑真是懷疑自己走的路到底是不是正確的。作為一個土生土長數學系學生,卻對數學毫無興趣,沒事的時候就喜歡躲在圖書館看看有關計算機的書。有時候期末考試時候會掛個一兩門的數學專業課,有時候真希望數學課本上這一個個繁瑣的證明是用程式碼寫的。自己幾乎丟掉了本專業的一切,去全身心

C語言入門運算子、sizeof運算子、if表示式

型別轉換、型別提升 #include <stdio.h> void test(); int main(int argc, const char * argv[]) { // 1.型別轉換 /* // int 佔用4個位元組 double

c++智慧指標shared_ptr和new結合使用

shared_ptr和new結合使用 我們除了使用make_shared來初始化一個智慧指標,還可以使用new返回的指標來初始化智慧指標。 shared_ptr<int> p1(new int(42));//p1指向一個值為42的int sh

C# MVC的部落格開發註冊

在做註冊的時候博主遇到了個很坑爹的問題那就是本地傳送郵件正常可是搬運到阿里雲伺服器傳送郵件就gg了查詢了很久才知道阿里雲預設是把25傳送郵件埠給封了也就是說放在阿里雲伺服器的傳送郵件是無法以無ssl加密的方式傳送的,必須通過ssl家裡的465埠去傳送郵件然後我們呼叫封裝好Ma