https://sourceforge.net/p/predef/wiki/Architectures/


gcc에서는 이정도면 될듯하다.

intel계열

#if defined(__i386__)

#if defined(__x86_64__)

arm 계열

32bit

#if defined(__thumb__)

#if defined(__arm__)

64bit

#if defined (__aarch64__)

Microsoft 오피스 패스워드 검증과 문서 암호 해제
 
오피스 문서 포맷에 걸린 패스워드 검증과 문서 암호 해제에 대하여 알아봅니다.
 
테스트 환경 : Windows 7 & Office 2013 (엑셀 및 워드)
 
# 패스워드 검증 
 
먼저, 패스워드를 걸은 문서를 준비합니다.
오피스에서 패스워드를 설정할때 읽기 패스워드와 쓰기 패스워드를 설정해야 하는데 본 포스팅에서는 읽기 패스워드 검증만 다룹니다.
 
SSView.zip
다운로드

오피스 문서의 구조를 볼 수 있는 Structured Storage Viewer로 문서 파일을 열어보면, EncryptionInfo에서 암호화 정보를 XML로 확인할 수 있습니다. 제 문서의 경우는 아래와 같았습니다.

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<encryption xmlns="http://schemas.microsoft.com/office/2006/encryption" 
xmlns:p="http://schemas.microsoft.com/office/2006/keyEncryptor/password"
xmlns:c="http://schemas.microsoft.com/office/2006/keyEncryptor/certificate">
<keyData 
	saltSize="16" 
	blockSize="16" 
	keyBits="256"
	hashSize="64"
	cipherAlgorithm="AES"
	cipherChaining="ChainingModeCBC"
	hashAlgorithm="SHA512" 
	saltValue="KtwuzFCcK6QP3ysDp0c9VA=="
/>
<dataIntegrity 
	encryptedHmacKey="huc0j3uogWrKgic0aUl1dcGY+ESN0MhIH59PX+uBVwFr5qlqthL/StMxY4Lmt+WmBB3I1eAM1G1kinPDnwshyg==" 
	encryptedHmacValue="uNQ9sZRZglMpRUFmsymsm7QCTC0IJy0PD6Pw+9ymrAAdJN+Lz1DuJlHyCuMr9L9appVn4Iy8QbDPG6WyTVoVyQ=="
/>
<keyEncryptors>
<keyEncryptor uri="http://schemas.microsoft.com/office/2006/keyEncryptor/password">
<p:encryptedKey 
	spinCount="100000" 
	saltSize="16" 
	blockSize="16"
	keyBits="256" 
	hashSize="64" 
	cipherAlgorithm="AES"
	cipherChaining="ChainingModeCBC"
	hashAlgorithm="SHA512" 
	saltValue="IdxU1HZJTfqRJ2lxI0JL2A==" 
	encryptedVerifierHashInput="+VL6xUT+JSrrgz9TZzM0uw==" 
	encryptedVerifierHashValue="2nEZi/gDl/2/K6Bp77YQfgHVmzucUdpK6vcv8vnPZcaZPrdtgx84AsbpqTLs8AMDNmB4QvCj7Iww+o0cmG+G7g==" 
	encryptedKeyValue="rRU8RZoSDlX9ZYGx+bJsCVh8WVeSmbAzttbNKzuT27U="
/>
</keyEncryptor>
</keyEncryptors>
</encryption>
 
아래 링크에 각 항목에 대한 설명이 있습니다.
 
읽기 패스워드를 검증하기 위해선 아래의 keyEncryptor 구조만 보면 됩니다. 
대략 살펴보면 반복 해시 10만번, salt 16바이트, AES256-CBC, SHA512 정도가 보입니다.
해당 정보들은 오피스 버전마다 다릅니다. 버전이 올라갈수록 암호화 강도도 세집니다.
(오피스 2007의 경우 반복 해시 0번에 SHA을 사용합니다.)
 
패스워드를 검증하는데 필요한 항목은 saltValue, encryptedVerifierHashInput, encryptedVerifierHashValue 이 세가지 입니다. 디코드하면 각각 16바이트, 16바이트, 64바이트입니다. 
 
salt는 사용자 입력 패스워드에 덧붙이는 랜덤 난수 생성 값으로 복호화 시 IV에 사용됩니다.
encryptedVerifierHashInput와 encryptedVerifierHashValue는 암호화 된 검증용 값들로 패스워드 해시로 유도한 대칭키로 복호화 한 후 패스워드가 올바른지 검증하는데 사용합니다.
 
패스워드를 검증하는 일련의 과정을 간략하게 도식화하면 아래와 같습니다.

 

[키 생성]

 

[키 검증]

 

첫번째 그림은 키 생성부입니다. 2개의 대칭키(복호화 키)를 뽑아내고 있습니다. 1 ~ 5)번까지의 과정입니다. 두번째 그림은 키 검증부입니다. 6 ~ 8)번까지의 과정입니다.

 

1) 16바이트 salt와 사용자 입력 패스워드를 sha512 해시(이하 해시)합니다.

2) 현재의 spin count를 입력하고 1)에서 생성한 해시를 붙입니다. (spin count (4바이트) + hash (64바이트))

3) 2)를 해시하고 spin count 뒤에 붙입니다. 이를 10만번 반복합니다. 최종적으로 패스워드 해시가 생성됩니다.

 

4) hash input 블록키를 패스워드 해시 뒤에 붙이고 해시합니다. 해당 해시는 encryptedVerifierHashInput의 대칭키가 됩니다.

5) hash value 블록키를 패스워드 해시 뒤에 붙이고 해시합니다. encryptedVerifierHashValue의 대칭키가 됩니다.

이제 얻어낸 키로 암호화 된 2개의 데이터를 복호화 해야 합니다.

AES 256비트와 CBC모드를 사용중이며 IV는 32바이트인데 salt (16바이트) + 패딩 0 (16바이트)로 되어 있습니다.

6) 4, 5)에서 얻어낸 각각의 대칭키를 넣고 복호화를 하여 16바이트 / 64바이트 데이터를 얻습니다.

7) 복호화 된 hash input 데이터를 해시한 후 복호화 된 hash value와 비교합니다.

8) 일치하면 올바른 패스워드입니다. 

 
# 문서 암호 해제 
 
복호화를 하기 전에 원본 문서 길이(복호화 길이)와 암호화된 문서 데이터를 알아야 합니다.
 
 
문서의 구조를 보면 EncryptedPackage 라는 항목이 있는데 원본 문서를 암호화 한 데이터가 들어가 있는 항목입니다.
첫번째 8바이트는 복호화 길이로 0x2071 = 8305바이트를 포함한다고 명시되어 있습니다.
암호화 된 데이터의 위치는 오프셋 0x8부터 끝까지입니다.
 
다시 xml구조를 봅니다. 문서를 복호화하는데 필요한 항목은 패스워드 검증할 때와 조금 다릅니다. 
keyEncryptor 구조의 encryptedKeyValue와 keyData 구조의 saltValue만 있으면 됩니다.
 
encryptedKeyValue는 암호화 된 대칭키입니다. 이 키로 문서를 복호화합니다. saltValue는 IV를 생성할 때 사용하는 salt입니다. 디코드를 하면 각각 32바이트, 16바이트입니다.
 
복호화 시 중요한 점은 문서 전체를 한번에 복호화 하는 것이 아닌 블록 단위 (4096바이트)로 합니다. 이 과정에서 IV는 매번 다른 값을 사용합니다.
 
1) key 블록키를 패스워드 해시 뒤에 붙이고 해시합니다. 해당 해시는 encryptedKeyValue의 대칭키가 됩니다. (블록키는 소스를 참조)
 
2) 1)에서 얻어낸 키로 복호화를 하여 32바이트 대칭키를 얻습니다.
 

 

3) IV연산은 16바이트 salt 에 4바이트 블록키를 더해서 생성합니다. 디폴트 블록키는 0이며 한 사이클당 1씩 증가합니다.

4) salt+블록키 = 20바이트를 해시합니다.

5) 해시된 데이터를 32바이트 컷합니다. (해시에 1 2 3  ... 64가 담겼다고 가정할 경우 32에서 컷) 해당 데이터를 IV로 사용합니다.
 
6) 대칭키와 IV, 그리고 암호화된 문서 블록(4096바이트)를 가지고 복호화합니다.
 
7) 3)부터 N번만큼 복호화를 반복합니다. 마지막 복호화의 길이는 원본문서길이 % 블록 사이즈입니다. 원본 길이가 8305이면 N은 3, 마지막 암/복호화 길이는 113입니다.
 
복호화된 데이터는 오피스에서 바로 오픈할 수 있습니다.
 
#include "stdafx.h"
#include <Windows.h>
#include <openssl/sha.h>
#include <openssl/aes.h>
#include "base64.h"

// 사용자 입력 패스워드 (unicode)
#define Password L"1234"

/* Input XML */
// From KeyData
#define SaltValue "PyRz/rrl5W3f8APOTTRqEg=="

// From KeyEncryptor
#define Salt "I9I1XvYqB2CZ/Xj/Ktt8tg=="
#define EncryptedVerifierHashInput "CoY5oPNs2r0eNXgnGxpVSA=="
#define EncryptedVerifierHashValue "oDHZqZdAG/ues/73uvAOL4yG2HlILGxIO2E0kfJ/QWFqO1E9JuX8jBvtR93o26DR0UimnRRI5NjarERGk4ajfA=="
#define EncryptedKeyValue "TblBTCEtWuGcM9qdLMMCkGNhJXiTNUcgg486ykUr7KA="
#define SPIN_COUNT 100000

#define MAX_FILE_SIZE 999999


void Decrypt2(
	IN PBYTE pbySalt, // salt
	IN PBYTE pbyKey, // 복호화용 대칭키
	IN PBYTE pbyEncryptedContent, // 암호화 된 컨텐츠
	OUT PBYTE pbyDecryptedContent, // 복호화 된 컨텐츠
	IN int cbDecryptLength // 복호화 된 문서 길이	
	)
{

	DWORD dwBlockSize = 4096; // 블록 길이
	DWORD dwRead = 0; // 총 복호화 한 길이
	int n = (cbDecryptLength + dwBlockSize - 1) / dwBlockSize; // 복호화 횟수
	for (int i = 0; i < n; i++)
	{
		DWORD dwLen = 0;
		// 한 블록당 복호화 할 길이를 구한다.
		if (i < n - 1)
		{
			dwLen = dwBlockSize;
		}
		else
		{
			dwLen = cbDecryptLength % dwBlockSize;			
		}
	
		// iv + blockkey
		BYTE temp[20] = { 0, };
		// 블록키는 1씩 증가한다.
		BYTE byBlockKey[4] = { 0, };
		memcpy(byBlockKey, &i, sizeof(int));
		
		memcpy(temp, pbySalt, 16); // 16바이트를 salt로 채운다.
		memcpy(temp + 16, byBlockKey, 4); // 블록키를 iv뒤에 4바이트 이어붙임

		// 64바이트 iv hash생성
		BYTE ivhash[64] = { 0, };
		SHA512_CTX ctx;
		SHA512_Init(&ctx);
		SHA512_Update(&ctx, temp, 20);
		SHA512_Final(ivhash, &ctx);

		BYTE iv[32] = { 0, }; // iv는 32바이트이다.
		AES_KEY akey;
		memcpy(iv, ivhash, 32); // IV 해시에서 32바이트만큼 복사한다.
		memset(&akey, 0, sizeof(AES_KEY));
	
		// iv와 대칭키를 설정한다.
		if (AES_set_decrypt_key(pbyKey, 256, &akey) < 0)
		{
			printf("error\n");
			return;
		}
	
		AES_cbc_encrypt(pbyEncryptedContent + (i*dwBlockSize), (unsigned char*)pbyDecryptedContent+dwRead, dwLen, &akey, iv, AES_DECRYPT);
		dwRead += dwLen;
	}
}
void Decrypt(
	IN PBYTE pbySalt, // salt
	IN PBYTE pbyKey, // 복호화용 대칭키
	IN PBYTE pbyEncryptedContent, // 암호화 된 컨텐츠
	OUT PBYTE pbyDecryptedContent, // 복호화 된 컨텐츠
	IN int cbDecryptLength // 복호화 된 검증값 길이
	)
{
	BYTE iv[32] = { 0, }; // iv는 32바이트이다.
	AES_KEY akey;
	memcpy(iv, pbySalt, 16); // 16바이트를 salt로 채운다.
	memset(&iv[16], 0, 16); // 16바이트 이후를 0으로 채운다.
	memset(&akey, 0, sizeof(AES_KEY));

	// iv와 대칭키를 설정한다.
	if (AES_set_decrypt_key(pbyKey, 256, &akey) < 0)
	{
		printf("error\n");
		return;
	}
	AES_cbc_encrypt(pbyEncryptedContent, (unsigned char*)pbyDecryptedContent, cbDecryptLength, &akey, iv, AES_DECRYPT);
}

void GenPasswordHash(
	OUT PBYTE pbyHash, 
	IN PWCHAR pszPassword, 
	IN PBYTE pbySalt)
{
	// spin count를 입력해야하기 때문에 UINT형을 사용한다.
	UINT32 uiBuffer[(SHA512_DIGEST_LENGTH / sizeof(UINT32)) + 1] = { 0, };
	int len = wcslen(pszPassword) * 2; // 패스워드는 유니코드로 처리한다.
	SHA512_CTX ctx;
	SHA512_Init(&ctx);
	SHA512_Update(&ctx, pbySalt, 16);
	SHA512_Update(&ctx, pszPassword, len);
	SHA512_Final((BYTE*)&uiBuffer[1], &ctx);

	// spin_count = 100000
	for (int i = 0; i < SPIN_COUNT; i++)
	{
		*uiBuffer = i; // spin count
		SHA512_Init(&ctx);
		SHA512_Update(&ctx, &uiBuffer, SHA512_DIGEST_LENGTH + 4 /*spin count buffer length */);
		SHA512_Final((BYTE*)&uiBuffer[1], &ctx);
	}
	memcpy(pbyHash, (BYTE*)&uiBuffer[1], SHA512_DIGEST_LENGTH);
}
void GenAgileEncryptionKey(
	IN PBYTE pbyHash,  // password 해시
	IN PBYTE pbyBlockKey, // 블록키
	OUT PBYTE pbyEncKey // 생성된 대칭키
	)
{		
	BYTE byHashWithKey[SHA512_DIGEST_LENGTH + 8] = { 0, };
	
	// password 해시 복사
	memcpy(byHashWithKey, pbyHash, SHA512_DIGEST_LENGTH);
	
	// 해시 뒤에 블록키 붙임
	memcpy(&byHashWithKey[SHA512_DIGEST_LENGTH], pbyBlockKey, 8);
	
	SHA512_CTX ctx;
	SHA512_Init(&ctx);
	SHA512_Update(&ctx, byHashWithKey, SHA512_DIGEST_LENGTH + 8);
	SHA512_Final(pbyEncKey, &ctx);
}


int _tmain(int argc, _TCHAR* argv[])
{
	/*----------------------------
		패스워드 검증
	-----------------------------*/
	// 블록 키 (고정값)
	BYTE byHashInputBlockKey[] = { 0xfe, 0xa7, 0xd2, 0x76, 0x3b, 0x4b, 0x9e, 0x79 };
	BYTE byHashValueBlockKey[] = { 0xd7, 0xaa, 0x0f, 0x6d, 0x30, 0x61, 0x34, 0x4e };

	// decode64 된 데이터
	BYTE bySalt[16] = { 0, }; 
	BYTE byEncryptedVerifierHashInput[16] = { 0, };
	BYTE byEncryptedVerifierHashValue[64] = { 0, };
		
	base64_decode(Salt, bySalt, 16);
	base64_decode(EncryptedVerifierHashInput, byEncryptedVerifierHashInput, 16);
	base64_decode(EncryptedVerifierHashValue, byEncryptedVerifierHashValue, 64);
	
	// 암호화 데이터를 복호화하는 대칭키
	BYTE byHashInputKey[SHA512_DIGEST_LENGTH] = { 0, }; 
	BYTE byHashValueKey[SHA512_DIGEST_LENGTH] = { 0, };

	// 패스워드 해시를 구함
	BYTE byPwHash[64] = { 0, };
	GenPasswordHash(byPwHash, Password, bySalt);
	
	// 대칭키 생성 (with password hash)
	GenAgileEncryptionKey(byPwHash, byHashInputBlockKey, byHashInputKey); 
	GenAgileEncryptionKey(byPwHash, byHashValueBlockKey, byHashValueKey); 
	
	// 복호화 
	BYTE byDecryptedVerifierHashInput[16] = { 0, }; 
	BYTE byDecryptedVerifierHashValue[64] = { 0, }; 
	Decrypt(bySalt, byHashInputKey, byEncryptedVerifierHashInput, byDecryptedVerifierHashInput, 16);
	Decrypt(bySalt, byHashValueKey, byEncryptedVerifierHashValue, byDecryptedVerifierHashValue, 64);
		
	// 복호화 된 검증용 해시 입력을 해시한다.
	BYTE byFinalHash[SHA512_DIGEST_LENGTH] = { 0, };
	SHA512_CTX ctx;
	SHA512_Init(&ctx);
	SHA512_Update(&ctx, byDecryptedVerifierHashInput, 16);
	SHA512_Final(byFinalHash, &ctx);

	// 해시 비교한다.
	int nCmp = memcmp(byFinalHash, byDecryptedVerifierHashValue, SHA512_DIGEST_LENGTH);
	if (0 == nCmp) printf("correct password!\n");
	else printf("incorrect password!\n");
	
	/*----------------------------
		문서 복호화
	-----------------------------*/
	// 블록 키 (고정값)
	BYTE byKeyBlockKey[] = { 0x14, 0x6e, 0x0b, 0xe7, 0xab, 0xac, 0xd0, 0xd6 };

	BYTE* byEncryptedFileBuffer = NULL;
	BYTE* byDecryptedFileBuffer = NULL;
	
	byEncryptedFileBuffer = (BYTE*)malloc(MAX_FILE_SIZE);
	byDecryptedFileBuffer = (BYTE*)malloc(MAX_FILE_SIZE);

	UINT64* pullDecryptLength = (UINT64*)malloc(sizeof(UINT64));
	
	// EncryptPackage 파일 오픈
	HANDLE hFile = CreateFile(L"D:\\EncryptedPackage2", GENERIC_READ, 0, NULL, OPEN_ALWAYS, 0, NULL);

	DWORD dwRead = 0;
	ReadFile(hFile, byEncryptedFileBuffer, MAX_FILE_SIZE, &dwRead, NULL);

	// 앞 8바이트에서 복호화 길이를 구한다.
	memcpy(pullDecryptLength, byEncryptedFileBuffer, 8);
	
	BYTE bySaltValue[16] = { 0, };
	BYTE byEncryptedKeyValue[32] = { 0, };

	base64_decode(SaltValue, bySaltValue, 16);
	base64_decode(EncryptedKeyValue, byEncryptedKeyValue, 32);

	// 대칭키 생성 (with password hash)
	BYTE byKeyValueKey[SHA512_DIGEST_LENGTH] = { 0, };
	GenAgileEncryptionKey(byPwHash, byKeyBlockKey, byKeyValueKey);
	
	// 대칭키를 복호화한다.
	BYTE byDecryptedKeyValue[32] = { 0, };
	Decrypt(bySalt, byKeyValueKey, byEncryptedKeyValue, byDecryptedKeyValue, 32);
	
	HANDLE hSaveFile = CreateFile(L"D:\\Decrypt", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
	// 문서를 복호화한다.
	Decrypt2(bySaltValue, byDecryptedKeyValue, &byEncryptedFileBuffer[8], byDecryptedFileBuffer, *pullDecryptLength);
	
	
	DWORD dwWritten = 0;
	WriteFile(hSaveFile, byDecryptedFileBuffer, *pullDecryptLength, &dwWritten, NULL);

	free(pullDecryptLength);
	getchar();
	return 0;
}

 

클라이언트 : 192.168.123.129 (Windows 7 + chrome)

서버 : 192.168.123.127 (Ubuntu + apache 기본 설정)

클라이언트의 웹 브라우저에서 http://192.168.123.127을 입력했을 시 TCP계층에서 어떤 데이터들이 오고가는지 와이어샤크를 통해서 간략하게 살펴봅니다. 

 와이어샤크 패킷 다운로드 

wireshark.pcapng


[클릭클릭 확대해서 봅니다]


[간략 표]



#1. 3-way 핸드셰이크

SYN : 통신 개시를 요청

ACK : 통신 확인에 대해 알겠다고 확인 응답

[No. 1] 클라이언트는 서버에게 통신 시작을 요청합니다. (SYN)

[No. 2] 서버는 알겠다고 응답함과 동시에 클라이언트에게 통신 시작을 요청합니다. (SYN & ACK)

[No. 3] 클라이언트는 서버에게 알겠다고 응답합니다. (ACK)


이 일련의 과정을 3-way 핸드셰이크라 합니다.


#2. web page 요청 및 다운로드

[No. 4] 악수(?)가 끝나고 난 후 클라이언트는 웹 페이지를 요청합니다.

[No. 5] 서버는 알겠다고 응답합니다.

[No. 6~14] 서버가 index.html을 클라이언트에 전송합니다. 총 7517바이트를 전송하는데 한번에 보내지 않고 잘라서 전송을 합니다. 여기서는 6개로 자르는데 각각의 덩어리를 세그먼트라 칭합니다. 여기서는 각 세그먼트당 1460바이트입니다. (1460바이트 * 5개 + 마지막 세그먼트 217바이트) 덩어리로 자른 후에 번호를 붙이게 되는데 0,1,2,3,4번 이렇게 순차적인 번호를 붙이는게 아니라 바이트로 번호를 매깁니다. 1, 1461, 2921, 4381, 5841, 7301번으로 나뉘어 있습니다. 이를 Sequence 번호라 합니다. 좀 더 부연설명을 하자면 xxx번 포트에서 연결 유지 중인 전체 데이터 중 몇 번째 바이트에 해당하는지 인덱싱하는 것입니다. 여기서는 이미 핸드셰이크에서 1바이트(No.2 패킷)가 추가되었으므로 0번 세그먼트가 아닌 1번 세그먼트(1바이트)부터 시작하는 것 입니다. 서버와 클라이언트의 Sequence 번호는 각각 인덱싱됩니다.


여기서는 서버가 2개의 덩어리를 보낸 후 제대로 데이터가 전달됐는지 확인응답을 받는 구조입니다. [No.8] 응답 패킷을 보면 Acknowledgment 번호(다음에 상대방으로부터 받아야 할 Sequence 번호)가 2921번이라고 나오는데 이는 서버로부터 2921바이트(1460바이트*2 + 1바이트(No.2 패킷의 SYN비트))까지 정상적으로 다운로드 하였다는 것을 의미합니다. 0번째바이트부터 계산되므로 2920번째 바이트까지라고 보면됩니다. (서버야 난 2920번째 바이트까지 무사히 받았고 그 다음엔 2921번째가 필요하니 패킷 내놔라)

그런데 잠깐.. 와이어샤크 덤프에서는 세그먼트는 5개만 보이는데 마지막 7301번은 어디에 있을까요? 그것은 200 응답의 [No. 13]의 패킷에 포함되어 있습니다.

No.13 패킷에는 분리된 세그먼트에 대한 정보도 포함되어 있습니다.

이 정보를 바탕으로 클라이언트에서 세그먼트들을 다시 합칩니다. 합친 내용을 아래 그림과 같이 브라우저가 출력합니다. 

[No. 13 패킷의 일부분]

추가적으로 [No. 4] & [No. 14]에 PSH (PUSH 비트)가 붙었는데 이는 애플리케이션 계층으로 토스하라는 의미입니다. (즉, Apache 혹은 크롬으로 토스)


#3. 통신 종료


FIN : 통신 종료를 요청

RST : 통신을 강제로 해제

[No. 15] 서버는 클라이언트에게 통신을 끝내자고 요청합니다. (FIN & ACK)

[No. 16] 클라이언트는 알겠다고 응답합니다. (ACK)

<< 16과 17사이에 수초 간의 텀이 있습니다. >> 

[No. 17] 클라이언트는 서버에게 통신을 끝내자고 요청합니다. (FIN & ACK)

[No. 18] 클라이언트는 통신을 강제로 해제합니다. (RST & ACK) (의도되지 않은 게 올라왔네요. 무시합니다.)

[No. 19] 서버는 클라이언트에게 알겠다고 응답합니다. No.17에 대한 응답입니다. (ACK)



1. windows 에서 리눅스를 설치할 파티션 만듦

2. 설치 시 현재 windows boot manager 설치되었다고 나옴. 첫번째 windows boot manager 어쩌고 옵션 선택

-> 빈공간에 우분투가 설치됨

3. 설치 완료 후 http://sourceforge.net/projects/boot-repair-cd/files/ 에서 iso를 받은 후 해당 iso로 usb 부팅

-> 이 방법을 사용하지 않으면 try ubuntu로 부팅 후 랜카드 잡고 boot-repair 설치하고 복잡함 (심지어 인터넷에 있는 방법으로는 없는 패키지라고 나옴)

4. 재부팅하면 boot repair 창이 뜨는데 recommended repair 선택 후 완료되면 ctrl_alt_t 를 눌러 reboot로 재부팅

5. windows 10 으로 부팅 후 cmd를 관리자 모드로 실행하여 

bcdedit /set "{bootmgr}" path \EFI\ubuntu\grubx64.efi

6. 재부팅하면 grub으로 멀티부팅 가능함


들어가며

필자는 이 노트북에 리눅스를 설치하기 위해 cent 7, fedora, ubuntu 를 설치해보았다.


cent 7.0 : 기본으로 제공하는 커널이 3.10이며 wifi 랜 카드를 설치하기 위해선 커널 패치가 필수이다.

그래픽 드라이버 설치 후 그놈 로그인 시 프리징 걸린다.

fedora : 부팅 시 프리징

ubuntu : 부팅 시 프리징, 그나마 제일 많은 Q/A가 인터넷에 있다. 그것을 토대로 설치하였다.


본 포스팅은 ubuntu 14.04.3 LTS 를 설치하는 법을 다룬다.


$ ubuntu 15.10를 설치하지 않는 이유 $

최신 디바이스 드라이버를 제공하며 별도로 랜 드라이버를 설치할 필요가 없으나,

그래픽 드라이버 설치 후 x window 로그인 시 에러가 발생한다. 이 이유를 xorg-server 버전의 문제로 생각하였으나,

352.63 드라이버가 1.18버전을 지원하고 ubuntu 15.10에는 1.17.2버전이 설치되어 있다. 미지원 버전 문제가 아님에도 에러가 발생한다.


# BIOS 에서 변경해야 할 몇가지가 있음

uefi with csm (uefi 시 부팅은 되나 프리징)

secure boot = disable (enable했을 시 설치 후 invalid 시그내처 문제로 부팅 안됨)

fast boot = disable

speed step = disable


# 설치 전

ubuntu 14.04.3 버전 cd 및 usb 삽입 후 부팅


grub 에서 install ubuntu 를 선택하고 e 를 눌러서 에디트 모드로 들어감

quiest splash --- 문장을 찾은다음 ---을 nomodeset으로 치환

F10으로 부팅


# 설치 후  


$ 부팅 시 멈출 경우 $

grub 메뉴로 빠진다음(부팅시 왼쪽 SHIFT키를 가만히 누르고 있으면 된다. 만약 그대로 프리징 될 경우 파워오프 후 될때까지 재도전)

#설치전 항목 수행 (메뉴로 빠지지 않고 가만히 놔두면 프리징 걸림)

부팅 후 sudo vi /etc/default/grub 을 치면

GRUB_CMDLINE_LINUX_DEFAULT="quiest splash"가 보이는데 splash 뒤에 nomodeset 추가

빠져나온뒤 update-grub으로 grub 갱신 후 재부팅

(만약 grub을 수정하지 않으면 ctrl_alt_F1 콘솔 진입 시 프리징이 걸린다.)


nvidia 드라이버 설치 후 nomodeset을 삭제한다.



1) wifi 드라이버 설치

https://wireless.wiki.kernel.org/en/users/Drivers/iwlwifi

이곳에서 Intel® Wireless 3165  드라이버를 다운로드 한다.

14.04.3은 커널 3.19버전을 사용하므로 적합한 버전을 다운로드 한다.


iwlwifi-3165-12.ucode <-- 이것을 받아도 무방하다.


압축 해제 후 파일명을 7265에서 3165으로 변경 후 /lib/firmware디렉토리에 복사한 후 재부팅하면 wifi가 잡힌다.

* 재부팅 없이 적용하는 방법

sudo modprobe -r iwlwifi

sudo cp iwlwifi-3165-12.ucode /lib/firmware

sudo modprobe iwlwifi


2) nvidia 드라이버 설치

lightdm을 별도로 종료하지 않아도 상관 없다. 

해보진 않았지만 lightdm 상의 소프트웨어 업데이트 기능으로도 가능할 것 같다.

sudo add-apt-repository -y ppa:xorg-edgers/ppa 

sudo apt-get update

sudo apt-get install nvidia-352 

reboot


재부팅 후 제대로 설치되었는지 확인해본다.

nvidia-settings


(인터넷 무수한 글을 살펴보면 nouveau를 disable하는것으로 보이지만 건들지 않아도 설치가 잘 되었다.)

(혹시 nouveau에 문제가 생기면 구글에 아주 많은 disable자료가 있다.)




+ Recent posts