어제는 늦게까지 백준 풀다보니 TIL을 작성하지 못했네요..ㅎ

대학원 들어와서 꼭 해야할 3가지에 대해서 생각해보았는데요.

학부때부터 제대로 공부하지 못해서 아쉬웠던 개발과 해킹에 대해서 다시 공부해보려고 합니다.

연구 메인 분야로 블록체인을 선택하였는데, 관련해서 생태계를 그리 잘 아는 것 같진 않아서 Web3 공부도 열심히 해야할 것 같아요.

 

최근에 교수님들과 미팅 및 면담을 하게 되면서 생각한건데 너무 한 분야만 집중하기 보다는 여러 분야를 접해보는 것도 좋은 방법 중의 하나일 것 같다는 생각이 들었습니다.

그리고 랩에서는 아이디어 제안하는 것을 매우 중요한 가치로 여기고 있어서 학부, 석사때부터 스스로 연구 주제를 발굴하는 연습을 하고 있습니다. 근데 정말 어렵더라구요. 괜찮은 아이디어 같은데?! 싶어서 조사해보면 이미 있고, 제가 알고 있는 것을 기반으로 새로운 것을 제안하는 것이 정말 어렵다고 생각했습니다. 어느날 미팅을 들어갔는데 교수님께서 생물학의 세포와 관련해서 말씀을 해주시더라고요. 듣고 놀랐습니다.

 

미팅을 함께 들어갔던 다른 분이 디지털 면역체계와 관련된 연구를 하고 계셨는데, 코멘트로 하셨던 말씀이

실제 우리 몸에서 균이 들어왔을 때 항원-항체 반응은 알고 있는 특정 균에 대해서 잡아먹고, 대식 세포는 균이든 좋은 세포든 모두 잡아 먹는 세포라고 하시면서 보안에서도 유사하게 적용할 수 있다. 이런 내용으로 말씀해주셨습니다.

저는 아이디어를 넓게 생각한다고 해도 보안 분야 중에서 다른 분야의 솔루션을 내가 하고 있는 분야에 적용해보면 어떨까?가 최선이었는데, 정말 다른 일상의 분야에서도 접목해서 생각해볼 수 있다는 것을 새롭게 깨닫게 되었습니다. 그래서 더욱이 하나에 집중하는 것도 좋지만, 뭐가 됐던 많이 보고 배우는 것이 좋겠다 싶더라구요.

 

서론이 길었는데, 어쨌던 요즘은 관심 분야를 넓혀보려고 하고 있습니다.

 

오늘 제가 코테 연습을 한다고 브론즈 문제부터 시작해보았는데, 연습삼아 해본 문제들에서도 배울 점이 있었습니다.
보통 python으로 사용자의 입력을 받을 때 input함수를 사용하잖아요. 근데 sys.stdin.readline()으로도 가능하더라구요.
input 함수는 input("prompt message") 이런식으로 프롬프트에 메시지를 입력할 수 있고, 해당 값이 출력되면서 사용자의 입력을 받게 되는데 거기서 약간의 지연이 발생한다고 합니다. 반복문으로 입력을 많이 받는 상황에서는 sys.stdin.readline()이 효율적이라고 하네요ㅎㅎ

 

브론즈 문제중에 다이얼이라는 문제가 있는데, 다른 write up을 보니 리스트에 문자열을 배치하거나 문자에 따른 시간을 미리 선언해두고 사용하더라구요.

다른 방법으로 풀고 싶어서 고민을 해보았는데, ASCII 문자열을 ord로 변환해서 3으로 나누었을 때 해당하는 시간에 매핑되도록 작성해볼 수 있었습니다.

import sys

def main():
    total_time = 0
    num = sys.stdin.readline().strip()
    arr = [3, 4, 5, 6, 7, 8, 9, 10]
    for i in range(len(num)):
        if num[i] == 'S' or num[i] == 'V' or num[i] == 'Y' or num[i] == 'Z':
            num_index = (ord(num[i])-62)//3
            total_time += arr[num_index-2]
        else:
            num_index = (ord(num[i])-59)//3
            total_time += arr[num_index-2]
    print(total_time)
            
        
if __name__ == '__main__':
    main()

생각했던 방법이 통해서 오! 하면서 풀었네요ㅎㅎ

 

알고리즘 단계별로 풀이를 진행하고 있는데, 실버전까진 하루에 한챕터씩 풀이해보려고 합니다!

그럼 오늘도 화이팅!

'TIL > TIL' 카테고리의 다른 글

2024년 10월 15일 (화)  (0) 2024.10.15

오늘부터 TIL을 작성해보려고 합니다.

블로그를 쉬는 동안 대학원에 입학하여 석사 생활을 하고 있는데요.

학부연구생을 하던 때에 수행하였던 논문 프로젝트에 대해서 해외 저널에 투고했고, Major Revision을 받았습니다.

관련해서 수정 작업과 함께 구현체 개발을 처음부터 해야하는 상황이라 이래저래 많이 바빴던 것 같아요.

PBFT의 확장성 문제를 개선하기 위한 아이디어를 제안하였는데요.

학부생때는 공저자로 프로젝트에 참여하였다가 현재는 1저자로 작업을 진행하고 있습니다.

 

이제 새로운 분야에 대해서 프로젝트를 수행하려고 하는데, 작년 내내 slither라는 스마트 컨트랙트 취약점을 정적 분석 기법으로 자동 탐지해주는 도구에 대해서 분석을 수행하였습니다.

하다보니 이쪽 분야에 관심이 생겨서 slither를 개선한 VSCode Extension을 개발하였는데, 직접 slither와 같은 도구를 개발해보고 싶더라구요!

드림 아카데미와 프로토콜 캠프를 병행하면서 해보려고 했었는데, 항상 시간이 아쉽다는 마음에 이번에는 졸업 논문까지 가져간다는 마인드로 처음부터 제대로 공부해보고 프로젝트를 진행해보려고 합니다.

 

그래서 어제 분석할 논문들 리스팅을 완료하였고, 오늘부터 하나씩 리뷰를 해보려고 합니다ㅎㅎ

화이팅해볼게요 :)

'TIL > TIL' 카테고리의 다른 글

2024년 10월 17일 (목)  (0) 2024.10.18

개요

  • css에서 여백을 주는 것은 marginpadding으로 구분할 수 있습니다.
  • margin바깥쪽 여백, padding안쪽 여백을 지정합니다.
    • padding은 여백만큼 크기가 더 커지게 됩니다.
    • 각 방향마다(상하좌우) 개별 속성을 지정할 수도 있습니다.

그림으로 한번 그려보았는데요.

 

[margin]

 

[padding]

  • padding은 header, container, container-left 모두 동일하게 작용하지만, 최적화를 위해서는 최상위 요소 보다는 직접적으로 padding 효과를 받는 요소에 넣는 것이 좋다고 합니다.

 

[전체]

 

 

예제 코드 - HTML

reset.css를 적용한 후에 진행하였습니다.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <link rel="stylesheet" href="./style.css">
    <link rel="stylesheet" href="./normalize.css">
</head>
<body>
    <div class="a">a 입니다.</div> 
    <div class="b">b 입니다.</div> 
</body>
</html>

margin과 padding 적용해보기

.a{
    background-color: pink;
    margin: 10px;
    border: 2px solid black;
}

.b{
    background-color: skyblue;
    border: 2px solid black;
    padding: 10px;
}

 

a에는 margin을, b에는 padding을 넣어보았습니다.

margin은 바깥쪽 여백을 잡아주기 때문에 바깥에 흰 여백이 생긴 것을 확인할 수 있습니다.

반대로, padding은 안쪽 여백을 잡아주고 있어 b가 상하좌우로 10px씩 더 커진 것을 볼 수 있네요.


개별 속성 지정해보기

상하좌우로 개별 속성을 지정해보겠습니다.

.a{
    margin-top: 10px; 
    margin-left: 10px; 
    margin-right: 10px; 
    margin-bottom: 10px; 
}

.b{
    padding-top: 10px;
    padding-left: 10px;
    padding-right: 10px;
    padding-bottom: 10px;
}

이렇게 top, left, right, bottom으로 각각의 여백을 설정할 수 있어요.

 

그렇지만 margin, padding 한 속성으로 개별 여백도 지정해볼 수 있습니다.

.a{
	/*       위   오른  아래  왼*/
	margin: 10px 50px 20px 0;
}
   
.b{   
	/*       위   오른  아래  왼*/
	padding: 10px 50px 20px 0;
}

 

이런식으로 설정할 수 있습니다!

결과 값은 그림과 같이 나타나게 됩니다. 

여백 정도에 따라서 예상하셨겠지만, 시계 방향으로 여백이 지정되네요!

 

 

또한, 속성을 2개만 기술한다면 첫 번째 값은 상하, 두 번째 값은 좌우 여백을 지정합니다.

.a{
	/*       상하  좌우  */
	margin: 10px 50px;
}
   
.b{   
	/*       상하   좌우  */
	padding: 10px 50px;
}

 

그렇다면, 가장 먼저 사용해보았던 margin: 10px; 이런식으로 하나만 작성한 것은 상하좌우 모두 10px씩 margin을 주는 것이라고 이해할 수 있습니다.


margin: auto를 이용하여 중앙 정렬하기

margin: auto 속성을 사용하면, 전체 width에서 좌우로 auto 여백을 가지기 때문에 영역 안에서 중앙으로 몰아주는 효과가 있습니다.

 

예제 코드

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <link rel="stylesheet" href="./style.css">
    <link rel="stylesheet" href="./normalize.css">
</head>
<body>
    <div class="a">
        <div class="b">중앙으로 정렬해보아요</div>
    </div>
</body>
</html>

 

.a{
    background-color: skyblue;
}

.b{
    width: 980px;
    background-color: pink;
    margin: auto;
}

 

이렇게 하위 태그가 선언되었을 때 하위 태그에 대해서 width를 설정해준 다음, margin: auto 속성을 부여하면 전체 width에 대해 중앙으로 정렬된 것을 볼 수 있습니다.


수직 중앙 정렬하기

번외로 marginpadding을 이용한 수직 중앙 정렬 방법도 실습해보았습니다.

margin: auto를 통해 좌우 중앙 정렬이 가능했는데요. 

여기에 padding을 추가하여 수직 중앙 정렬도 구현해볼 수 있습니다.

.a{
    background-color: skyblue;
    padding: 150px;
}

.b{
    width: 980px;
    background-color: pink;
    margin: auto;
    padding: 20px;
}

 

직전 html 코드에서 css에 padding을 추가해보았습니다.

 

이렇게 수직으로도 정렬된 결과를 확인해볼 수 있습니다.


🍀 추가로 공부해야 할 것
찾아보니 margin, padding에 음양수를 넣는 것이 달랐고, auto, collaspe를 적용할 수 있는게 달랐다.
관련해서 더 알아보자!

'Language Note > CSS' 카테고리의 다른 글

[CSS] reset.css  (2) 2024.01.07

브라우저 내에서 기본적으로 지정되어 있는 사항들

1. 웹브라우저에서는 기본적으로 margin이 부여되어 있습니다.(User-Agent StyleSheet)

  • reset.css나 body에 간단하게 margin/padding: 0;을 부여하고 시작하는게 좋습니다.
  • 브라우저마다 내장 스타일이 조금씩 다르기 때문에 그대로 두고 시작한다면 의도했던 것들이 제대로 보이지 않는 현상이 발생할 수 있습니다.

 

2. font-size16px로 지정되어 있습니다.

 

3. width, heightauto로 지정되어 있습니다.

  • width는 auto일 때 100%(화면 처음부터 끝까지)로 인식합니다.
  • height는 auto일 때 0부터 출발합니다.(내부에 들어있는 요소에 따라 자동적으로 height가 늘어나요)

이 중에서 reset.css에 대해 알아보았습니다.

대표적으로 크롬과 사파리에 대한 css를 찾아볼 수 있었는데요.

Chrome: https://chromium.googlesource.com/chromium/src/third_party/+/master/blink/renderer/core/html/resources/html.css

Safari: https://trac.webkit.org/browser/trunk/Source/WebCore/css/html.css

 

브라우저에서 정의한 스타일이 무엇인지 확인할 수 있습니다.


0. 기본 형태

먼저, 기본적으로 html div를 생성해서 background-color를 입혀보았습니다.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <link rel="stylesheet" href="./style.css">
</head>
<body>
    <div class="a">안녕하세요</div> 
</body>
</html>

 

.a{
    background-color: pink;
}

 

 

오호 정말 여백이 존재하네요


1. margin, padding 값 조정

body에 padding과 margin에 대해서 0을 설정하여 확인해봤습니다.

body{
    margin: 0;
    padding: 0;
}

.a{
    background-color: pink;
}

 

여백 없이 꽉 들어차 있는 결과를 확인할 수 있었습니다.


 

이렇게 브라우저 내에서 제공하는 기본적인 스타일을 제거하는 방법에는 크게 CSS NormalizeCSS Reset이라는 방법이 있습니다.

 

nomalize라는 방법은 어느정도 유용한 스타일은 유지하는 형태로 제공하고, hard reset은 모든 css를 삭제해버리는 방법입니다.

 


2-1. CSS Normalize

https://github.com/necolas/normalize.css/blob/master/normalize.css

 

대표적으로 알려져있는 normalize.css 코드입니다.

 

/*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */

/* Document
   ========================================================================== */

/**
 * 1. Correct the line height in all browsers.
 * 2. Prevent adjustments of font size after orientation changes in iOS.
 */

html {
  line-height: 1.15; /* 1 */
  -webkit-text-size-adjust: 100%; /* 2 */
}

/* Sections
   ========================================================================== */

/**
 * Remove the margin in all browsers.
 */

body {
  margin: 0;
}

/**
 * Render the `main` element consistently in IE.
 */

main {
  display: block;
}

/**
 * Correct the font size and margin on `h1` elements within `section` and
 * `article` contexts in Chrome, Firefox, and Safari.
 */

h1 {
  font-size: 2em;
  margin: 0.67em 0;
}

/* Grouping content
   ========================================================================== */

/**
 * 1. Add the correct box sizing in Firefox.
 * 2. Show the overflow in Edge and IE.
 */

hr {
  box-sizing: content-box; /* 1 */
  height: 0; /* 1 */
  overflow: visible; /* 2 */
}

/**
 * 1. Correct the inheritance and scaling of font size in all browsers.
 * 2. Correct the odd `em` font sizing in all browsers.
 */

pre {
  font-family: monospace, monospace; /* 1 */
  font-size: 1em; /* 2 */
}

/* Text-level semantics
   ========================================================================== */

/**
 * Remove the gray background on active links in IE 10.
 */

a {
  background-color: transparent;
}

/**
 * 1. Remove the bottom border in Chrome 57-
 * 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari.
 */

abbr[title] {
  border-bottom: none; /* 1 */
  text-decoration: underline; /* 2 */
  text-decoration: underline dotted; /* 2 */
}

/**
 * Add the correct font weight in Chrome, Edge, and Safari.
 */

b,
strong {
  font-weight: bolder;
}

/**
 * 1. Correct the inheritance and scaling of font size in all browsers.
 * 2. Correct the odd `em` font sizing in all browsers.
 */

code,
kbd,
samp {
  font-family: monospace, monospace; /* 1 */
  font-size: 1em; /* 2 */
}

/**
 * Add the correct font size in all browsers.
 */

small {
  font-size: 80%;
}

/**
 * Prevent `sub` and `sup` elements from affecting the line height in
 * all browsers.
 */

sub,
sup {
  font-size: 75%;
  line-height: 0;
  position: relative;
  vertical-align: baseline;
}

sub {
  bottom: -0.25em;
}

sup {
  top: -0.5em;
}

/* Embedded content
   ========================================================================== */

/**
 * Remove the border on images inside links in IE 10.
 */

img {
  border-style: none;
}

/* Forms
   ========================================================================== */

/**
 * 1. Change the font styles in all browsers.
 * 2. Remove the margin in Firefox and Safari.
 */

button,
input,
optgroup,
select,
textarea {
  font-family: inherit; /* 1 */
  font-size: 100%; /* 1 */
  line-height: 1.15; /* 1 */
  margin: 0; /* 2 */
}

/**
 * Show the overflow in IE.
 * 1. Show the overflow in Edge.
 */

button,
input { /* 1 */
  overflow: visible;
}

/**
 * Remove the inheritance of text transform in Edge, Firefox, and IE.
 * 1. Remove the inheritance of text transform in Firefox.
 */

button,
select { /* 1 */
  text-transform: none;
}

/**
 * Correct the inability to style clickable types in iOS and Safari.
 */

button,
[type="button"],
[type="reset"],
[type="submit"] {
  -webkit-appearance: button;
}

/**
 * Remove the inner border and padding in Firefox.
 */

button::-moz-focus-inner,
[type="button"]::-moz-focus-inner,
[type="reset"]::-moz-focus-inner,
[type="submit"]::-moz-focus-inner {
  border-style: none;
  padding: 0;
}

/**
 * Restore the focus styles unset by the previous rule.
 */

button:-moz-focusring,
[type="button"]:-moz-focusring,
[type="reset"]:-moz-focusring,
[type="submit"]:-moz-focusring {
  outline: 1px dotted ButtonText;
}

/**
 * Correct the padding in Firefox.
 */

fieldset {
  padding: 0.35em 0.75em 0.625em;
}

/**
 * 1. Correct the text wrapping in Edge and IE.
 * 2. Correct the color inheritance from `fieldset` elements in IE.
 * 3. Remove the padding so developers are not caught out when they zero out
 *    `fieldset` elements in all browsers.
 */

legend {
  box-sizing: border-box; /* 1 */
  color: inherit; /* 2 */
  display: table; /* 1 */
  max-width: 100%; /* 1 */
  padding: 0; /* 3 */
  white-space: normal; /* 1 */
}

/**
 * Add the correct vertical alignment in Chrome, Firefox, and Opera.
 */

progress {
  vertical-align: baseline;
}

/**
 * Remove the default vertical scrollbar in IE 10+.
 */

textarea {
  overflow: auto;
}

/**
 * 1. Add the correct box sizing in IE 10.
 * 2. Remove the padding in IE 10.
 */

[type="checkbox"],
[type="radio"] {
  box-sizing: border-box; /* 1 */
  padding: 0; /* 2 */
}

/**
 * Correct the cursor style of increment and decrement buttons in Chrome.
 */

[type="number"]::-webkit-inner-spin-button,
[type="number"]::-webkit-outer-spin-button {
  height: auto;
}

/**
 * 1. Correct the odd appearance in Chrome and Safari.
 * 2. Correct the outline style in Safari.
 */

[type="search"] {
  -webkit-appearance: textfield; /* 1 */
  outline-offset: -2px; /* 2 */
}

/**
 * Remove the inner padding in Chrome and Safari on macOS.
 */

[type="search"]::-webkit-search-decoration {
  -webkit-appearance: none;
}

/**
 * 1. Correct the inability to style clickable types in iOS and Safari.
 * 2. Change font properties to `inherit` in Safari.
 */

::-webkit-file-upload-button {
  -webkit-appearance: button; /* 1 */
  font: inherit; /* 2 */
}

/* Interactive
   ========================================================================== */

/*
 * Add the correct display in Edge, IE 10+, and Firefox.
 */

details {
  display: block;
}

/*
 * Add the correct display in all browsers.
 */

summary {
  display: list-item;
}

/* Misc
   ========================================================================== */

/**
 * Add the correct display in IE 10+.
 */

template {
  display: none;
}

/**
 * Add the correct display in IE 10.
 */

[hidden] {
  display: none;
}

이렇게 나타나겠네요.


2-2. CSS Reset

https://cssdeck.com/blog/scripts/eric-meyer-reset-css/

완전히 삭제해버리는 reset은 에릭 마이어씨의 css reset이 유명한데요.

 

/* http://meyerweb.com/eric/tools/css/reset/ 
   v2.0 | 20110126
   License: none (public domain)
*/

html, body, div, span, applet, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
a, abbr, acronym, address, big, cite, code,
del, dfn, em, img, ins, kbd, q, s, samp,
small, strike, strong, sub, sup, tt, var,
b, u, i, center,
dl, dt, dd, ol, ul, li,
fieldset, form, label, legend,
table, caption, tbody, tfoot, thead, tr, th, td,
article, aside, canvas, details, embed, 
figure, figcaption, footer, header, hgroup, 
menu, nav, output, ruby, section, summary,
time, mark, audio, video {
	margin: 0;
	padding: 0;
	border: 0;
	font-size: 100%;
	font: inherit;
	vertical-align: baseline;
}
/* HTML5 display-role reset for older browsers */
article, aside, details, figcaption, figure, 
footer, header, hgroup, menu, nav, section {
	display: block;
}
body {
	line-height: 1;
}
ol, ul {
	list-style: none;
}
blockquote, q {
	quotes: none;
}
blockquote:before, blockquote:after,
q:before, q:after {
	content: '';
	content: none;
}
table {
	border-collapse: collapse;
	border-spacing: 0;
}

엥 근데 원본 링크에 접속이 안되네요 .. 

 

이 외에도 다양한 방법이 있는 것 같아요

https://velog.io/@teo/2022-CSS-Reset-%EB%8B%A4%EC%8B%9C-%EC%8D%A8%EB%B3%B4%EA%B8%B0#%EA%B7%B8%EB%9E%98%EC%84%9C-%EB%AD%98-%EC%93%B0%EB%A9%B4-%EC%A2%8B%EC%9D%84%EA%B9%8C

 

2022 CSS Reset 다시 써보기!

..2022년 지금은 CSS Reset을 어떻게 만들어야 할까? 하는 생각이 들었습니다. 그래서 여러가지 관련자료와 애플, 네이버, 다음, 인프런, 오늘의 집, MS, 에어비엔비, 디스코드, 슬랙등의 CSS를 보면서

velog.io

 

이 분의 블로그를 통해서 많이 배웠네요!

 

조금 더 공부하면서 세부 내용들을 배워봐야겠습니다 :)

'Language Note > CSS' 카테고리의 다른 글

[CSS] margin과 padding  (0) 2024.01.07

티스토리에서 제공하고 있는 서체를 변경하고 싶은 마음이 들어서 폰트부터 찾아봤습니다.

기존에 사용하던 고딕체..

 

나름 바꿔본게 본고딕이었네요😂

티스토리 편집할 때도 프리뷰를 옆에 두고 실시간으로 볼 수 있었으면 좋겠습니다 🥲 좀 많이 불편하네요

 

저는 ppt 작업하면서 깔끔한 고딕체 느낌을 좋아하는데, ko pub 돋움체였나? 그걸 가장 좋아합니다ㅎㅎ

아쉽게도 웹폰트로 사용하는 건 없더라고요..

 

그래서 눈누에서 맘에 드는 폰트들을 폭풍 서치해봤습니다.

 

저는 그중에서도 둘기마요고딕을 선택했어요!


폰트 검색

https://noonnu.cc/

 

눈누

상업용 무료한글폰트 사이트

noonnu.cc

저는 눈누에서 마음에 드는 폰트를 골라봤는데요.

 

이런식으로 굉장히 다양한 폰트들이 존재합니다.

 

한가지 잘 살펴보셔야 하는 것은

이런식으로 웹폰트 사용에 내용이 있어야 합니다.


티스토리 스킨 편집하기

https://[내 블로그 이름].tistory.com/manage/design/skin/edit#/source/

본인 블로그 주소에 맞게 이동해볼까요? 클릭을 통해 이동하고 싶다면,

 

https://0secusik0.tistory.com/69#:~:text=%ED%8B%B0%EC%8A%A4%ED%86%A0%EB%A6%AC%20%EC%8A%A4%ED%82%A8%20%ED%8E%B8%EC%A7%91%EC%9C%BC%EB%A1%9C%20%EC%A7%81%EC%A0%91%20%EC%A0%81%EC%9A%A9%ED%95%B4%EB%B3%B4%EA%B8%B0

 

[Tistory] 코드 블럭 테마 변경하기

오랜만에 블로그를 작성하려고 하니 마음에 들지 않는 테마들 때문에 글쓰고 싶은 마음도 사라지는... 직접 블로그 사이트를 만들기 전에 기존 티스토리 테마를 조금씩 바꿔보려고 합니다. 가장

0secusik0.tistory.com

제가 업로드 했던 게시글 참고해주시면 되겠습니다.

 

css 탭에서 원하는 폰트에 대해서 눈누에서 복사한 코드를 넣어 주시면 됩니다.

 

아! 여기서 끝은 아니고, 서체는 font-family로 설정하게 되는데 기존에 작성되어 있던 부분들을 변경해주는 작업이 필요합니다.

 

@font-face 하위에 보이는 font-family: [폰트 이름] 에서 폰트 이름을 복사해주세요.

Ctrl+F를 통해 서치 창을 확인할 수 있는데 font-family를 검색해줍니다.

 

이런식으로 찾을 수 있어요

 

여기서 제가 넣고자 하는 폰트 이름인 Dovemayo_gothic을 넣어줬습니다.


에러 사항

font-family를 모두 바꿔주었는데 볼드 처리한 글꼴만 바뀌었습니다.

 

 

기존에 이렇게 평문으로 작성한 것에 대해서는 글꼴이 바뀌지 않았고,
개발자 도구를 열어서 확인해보니 글이 작성된 것이 span 태그 안에 있었습니다.
<span style="font-family: 'Noto Sans', 'Noto Sans KR';> 글 내용 </span>

 

element style이 적용되어 있어서 제가 넣은 css가 동작하지 않았습니다.

관련하여 구글링을 해보았는데요.

 

 

element.style이란?

  • 읽기 전용으로 인라인으로 정의된 스타일 속성
  • 읽기 전용이므로 CSSStyleDeclaration을 정의할 수 없다.
  • CSSStyleDeclaration.cssText를 통해 덮어쓸 수 있다.
<span style="font-family: 'Noto Sans', 'Noto Sans KR';> 글 내용 </span>

 

앞서 말씀드린 인라인 스타일에 대해 말하는 것 같았습니다.

 

https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/style

 

HTMLElement: style property - Web APIs | MDN

The read-only style property of the HTMLElement returns the inline style of an element in the form of a live CSSStyleDeclaration object that contains a list of all styles properties for that element with values assigned only for the attributes that are def

developer.mozilla.org

 

사전에 미리 적용되어 있는 인라인 스타일이라 어떻게 제거해야 할 지 고민이 되었습니다.

찾아보니 !important 속성을 추가하거나 javascript를 이용하여 수정 및 제거를 할 수 있더라고요!

 

important을 남발하면 안되긴하지만.. 간단하게 해결하기 위해서 important를 사용하였습니다.

참고로 javascript로는

document.querySelector('#선택자').removeAttribute('style');

이런식으로 쓸 수 있다고 합니다.

 

텍스트에 입혀지는 태그들에 전부다 넣어줬어요

근데 important 한번 들어가고 나서 저 css 들을 지워봤는데도 잘되네요 영구적인걸까요?

 

뭔가 제 생각에 제가 한 것처럼 p, span, h1, h2, ... 이부분이랑 #text가 필요치 않은 것 같긴해요

body, input, textarea 부분에만 잘넣어줘도 되지 않을까.. 싶네요

 

아! 그리고 important를 넣어주니 기존에 span 태그 안에 작성되던 글들이 모두 p태그 안에 작성되고 있었습니다.

 

신기한 일이 생겼네요. 이유는 왜그런지 아직 모르겠어요. 아시는 분 있으면 댓글 남겨주세요 :)


결과물

최종적으로는 이렇게 원하는 형태로 모든 글꼴이 변경되었습니다!

 

참고로 폰트 색이나 크기는 스킨 편집 창의 CSS 탭에서 font-size, color 이런 속성들을 검색해서 원하는 크기나 색상으로 조정하시면 됩니다 !

'Tistory' 카테고리의 다른 글

[Tistory] 코드 블럭 테마 변경하기  (2) 2024.01.07

오랜만에 블로그를 작성하려고 하니 마음에 들지 않는 테마들 때문에 글쓰고 싶은 마음도 사라지는...

직접 블로그 사이트를 만들기 전에 기존 티스토리 테마를 조금씩 바꿔보려고 합니다.

가장 먼저 해본 것은 코드 블럭!

기존 코드 블럭에 대해서 syntax highlight 테마중 default로 사용하고 있어서 굉장히 마음에 안들었어요..

저는 파스텔톤이나 무채색을 좋아하거든요ㅎㅎ..

제가 하고 싶었던 것 다음과 같아요

 

1. 코드 블럭 색상 테마 변경하기
2. 라인 번호 추가
3. 코드 블럭 접기
4. 줄바꿈에 대한 제어
5. 코드 복사 버튼

 

 

마침 관련해서 구글링해보았는데, 아래의 분께서 정리를 잘해주셨더라고요! 저도 따라하면서 조금 더 커스터마이징 해보았습니다.

https://jinyh.tistory.com/10

조금 더 해보고 싶은 것이 있다면 code 실행에 대한 result 보이게 하는 것이에요.

codepen에서는 embed 링크로 제공하고 있지만, mdn docs에서 보이는 것처럼 직접 만들어보고 싶다는 생각이 들었습니다!

그리고 요즘 옵시디언으로 문서들을 정리하다보니 마크다운에 html 요소들을 나름 많이 넣을 수 있어서 기본 문법 외에도 많은 것들을 활용할 수 있더라고요. 그런 것들을 버튼으로 조금더 스타일링할 수 있는 마크다운 에디터+프리뷰어를 제작하고 싶다는 생각을 하고 있습니다.

아직은 실력이 부족해서 어렵겠지만 조만간 꼭 도전할 예정입니다!

 

어쨌든 저도 성공했으니까 차근히 따라오시면 쉽게 넣으실 수 있을거에요 :)


티스토리 내 테마 사용하기

우선 티스토리에서는 8가지의 코드 블럭 테마를 제공하고 있습니다.

https://[내 블로그 이름].tistory.com/manage/plugins

본인 블로그 주소에 맞게 이동해볼까요? 클릭을 통해 이동하고 싶다면,

[톱니바퀴 모양 (블로그 관리 홈으로 이동해요)] - [왼쪽 사이드 바의 플러그인 클릭]으로 이동할 수 있어요!

 

아래로 조금 내려보면 코드 문법 강조라는 플러그인이 있는데요.

 

여기서 테마를 선택할 수 있어요. 하지만 미리보기 기능이 없어서 하나씩 적용해봐야 하는 ..

 

제가 한번 정리를 해봤는데요. 저는 사실 이중에서 마음에 드는게 없었어요.

왜냐하면 저는 우선 블로그 전체가 흰 배경인데 코드 블럭까지 흰바탕이면 구분이 잘가지 않고 눈이 아파서 다크모드였으면 좋겠고 너무 쨍한 색은 싫었거든요!


highlight.js를 이용한 테마 변경

highlight.js 에서는 굉장히 다양한 테마를 제공하고 있는데요.

링크의 데모 페이지에서 언어와 테마를 선택하여 프리뷰를 확인해볼 수 있습니다.

여기서 마음에 드는 테마를 고르면 될 것 같아요.

 

그런데 유의할 점은 highlight.js를 사용하기 위해서는 티스토리에서 제공하고 있는 코드 문법 강조 플러그인은 해제해주셔야 합니다.

 

https://highlightjs.org/demo

 

Demo - highlight.js

...

highlightjs.org

 

저는 마음에 드는게 꽤나 있어서 뭘 골라야 하나 고민이 됐네요.

저는 여러 언어에 대해서 테스트 해보고 고르게 되었는데,

python, css, javascript, markdown, c, json 정도 확인해보고 골랐어요.

(보다보니 전부다 봐버린..)

제가 고른건 접은 글 안에 있어요!

 

더보기
  • base16-ashes
  • base16-circus
  • base16-framer
  • base16-material-darker
  • base16-pop
  • base16-porple
  • base16-qualia
  • base16-seti-ui
  • base16-snazzy
  • base16-summerfruit-dark
  • base16-windows-10
  • base16-windows-high-contrast
  • base16-zenburn
  • felipec
  • hybrid
  • ir-black
  • lioshi
  • nord
  • stackoverflow-dark
  • tokyonight
  • rainbow

 

저는 이중에서 nord를 선택하였습니다.

고르셨다면 아래의 링크에서 cdnjs를 복사해주세요!

(하이라이트 링크를 복사했더니 링크 보양이 이상하게 보이는데 정상 링크입니다.)

https://highlightjs.org/#usage:~:text=our%20README.-,As%20HTML%20Tags,-cdnjs

 

highlight.js

Usage highlight.js can be used in different ways such using CDNs, hosting the bundle yourself, as a Vue plug-in, as ES6 modules, with Node.js, and web workers. See our README on GitHub for more details. As a Module Highlight.js can be used with Node on the

highlightjs.org

 

<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/default.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js"></script>

<!-- and it's easy to individually load additional languages -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/languages/go.min.js"></script>

<script>hljs.highlightAll();</script>

이걸 가져오시면 되는데요! 

제가 넣어보니 가장 마지막 script 태그가 안먹는건지 테마가 안씌워지더라고요.

 

  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/nord.min.css">
  <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js"></script>

  <!-- and it's easy to individually load additional languages -->
  <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/languages/go.min.js"></script>
  <script>hljs.initHighlightingOnLoad();</script>

그래서 저는 이렇게 넣어줬습니다.

 

넣는 방법 알려드릴게요.


티스토리 스킨 편집으로 직접 적용해보기

블로그 관리 홈에서 스킨 편집 탭을 클릭해주세요

 

오른쪽 화면에서 html 편집이라는 버튼을 찾을 수 있습니다. 클릭해주세요

 

이런식으로 HTML 파일이 보이실텐데요.

가장 상위의 <html> 태그 아래에 <head> 태그가 있습니다.

<head> ~~~ 다른 태그들 </head> 형태로 구성이 될텐데, head 태그 안에

  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/nord.min.css">
  <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js"></script>

  <!-- and it's easy to individually load additional languages -->
  <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/languages/go.min.js"></script>
  <script>hljs.initHighlightingOnLoad();</script>

아까 복사하였던 cdnjs를 넣어주세요!

 

참고로 첫 줄의 

<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/default.min.css"> 
이 부분의 default 자리에 마음에 드는 테마의 이름을 넣어주시면 됩니다. 
테마에 - 로 단어가 연결되어 있다면 그대로 stackoverflow-dark.min.css 이런식으로 넣어주시면 돼요.
저는 nord 테마를 선택했기 때문에 nord라고 작성하였습니다.

 

그런데 한가지 이슈가 있었어요. 다른 테마들은 잘 적용되었는데 base16-[이름] 형태인 테마는 적용이 안되더라고요.. 이유는 아직 못찾았습니다. 아시는 분 계시면 답글 남겨주세요!

 

어쨌든 이렇게 코드 넣어주시고 적용을 누르시면 됩니다.

 

이렇게 원하는 테마를 적용할 수 있습니다 :)

'Tistory' 카테고리의 다른 글

[Tistory] 폰트 변경하기  (0) 2024.01.07
dreamhack의 [Background: Library - Static Link vs. Dynamic Link]를 토대로 정리하였으며, 추가적으로 덧붙인 내용입니다.

 

Dynamic Link에서는 PLTGOT이 필요함. Static Link 방식으로 컴파일하면 라이브러리가 프로그램 내부에 있어 별도로 함수의 주소를 알아내는 과정이 필요하지 않음. 그러나 Dynamic Link 방식으로 컴파일하면 라이브러리가 외부에 위치해 함수 주소를 알아오는 과정이 필요하게 됨.

 

PLT(Procedure Linkage Table)이란?

외부 library 함수를 사용할 수 있도록 연결해주는 table

PLT를 통해 다른 라이브러리에 있는 함수를 호출해 사용할 수 있음

 

GOT(Global Offset Table)이란?

PLT가 참조하는 table

PLT에서 호출하는 resolve 함수를 통해 구한 library 함수들의 절대 주소가 저장되어 있음

 


PLT와 GOT의 호출 관계

출처: https://bpsecblog.wordpress.com/2016/03/07/about_got_plt_1/

Dynamic Link 방식에서 프로그램이 함수를 호출하게 되면 PLT를 가장 먼저 참조하게 됨

PLT에서 GOT로 jump하게 되며, GOT에 기록된 실제 함수 주소(library에 기록되어 있음)를 호출하여 함수가 동작하게 됨

 

이는 1번째 호출인지, 아닌지에 따라 동작 과정에 차이가 있음

바이너리가 실행되면 ASLR에 의해 library가 임의의 주소에 mapping 됨
해당 상태에서 library 함수를 호출하면, 함수의 이름을 바탕으로 library에서 symbol들을 탐색하고 해당 함수의 정의를 발견하였을 때 그 주소로 실행 흐름을 옮김
→ 이 과정을 runtime resolve라고 부름

 

만약, 반복적으로 호출되는 함수 정의를 매번 탐색하게 된다면 이는 매우 비효율적임

이에 GOT이라는 table에 resolve된 함수의 주소를 저장하여 사용하고 있음 → 저장된 주소를 꺼내쓰기만 하면 되기 때문!

 

결론적으로 함수에 대해 1번째 호출하게 된다면, 다음과 같이 호출흐름을 그려볼 수 있음

✨함수 호출 → PLT 이동 → GOT 참조 → PLT로 재이동 → _dl_runtime_resolve 수행 → GOT에 실제 주소 저장 후 실제 함수 주소로 분기

출처: https://bob3rdnewbie.tistory.com/190

 

반대로, 함수의 최초 호출이 진행된 후 재호출하게 된다면 GOT에 저장된 실제 함수 주소를 참조하기만 하면 됨

✨ 함수 호출 → PLT 이동 → GOT 참조 → 실제 함수 주소로 jump

출처: https://bob3rdnewbie.tistory.com/190

 

위의 상황을 모두 조합하여 흐름을 figure로 확인해보면 아래와 같음

출처: https://bnzn2426.tistory.com/27


실습으로 알아보는 resolve 전후 과정

실습 코드

// Name: got.c
// Compile: gcc -o got got.c -no-pie

#include <stdio.h>

int main() {
  puts("Resolving address of 'puts'.");
  puts("Get address from GOT");
}
  • 코드는 단순히 puts 함수를 2번 호출하고 있음
    • 1번째 puts 함수2번째 puts 함수의 동작 과정은 상이할 것임! (1번째 puts 함수에서는 resolve 과정이 수행되기 이고, 2번째 puts 함수에서는 resolve 과정이 끝난 상태일 것)

 

gdb 동적 분석

main 함수

pwndbg> disass main
Dump of assembler code for function main:
   0x0000000000401136 <+0>:	endbr64 
   0x000000000040113a <+4>:	push   rbp
   0x000000000040113b <+5>:	mov    rbp,rsp
   0x000000000040113e <+8>:	lea    rdi,[rip+0xebf]        # 0x402004
   0x0000000000401145 <+15>:	call   0x401040 <puts@plt>
   0x000000000040114a <+20>:	lea    rdi,[rip+0xed0]        # 0x402021
   0x0000000000401151 <+27>:	call   0x401040 <puts@plt>
   0x0000000000401156 <+32>:	mov    eax,0x0
   0x000000000040115b <+37>:	pop    rbp
   0x000000000040115c <+38>:	ret    
End of assembler dump.
  • main+15, main+27에서 puts 함수를 호출하고 있음

 

puts 함수

pwndbg> disass puts
Dump of assembler code for function puts@plt:
   0x0000000000401040 <+0>:	endbr64 
   0x0000000000401044 <+4>:	bnd jmp QWORD PTR [rip+0x2fcd]        # 0x404018 <puts@got.plt>
   0x000000000040104b <+11>:	nop    DWORD PTR [rax+rax*1+0x0]
End of assembler dump.

resolve되기 전

pwndbg> start
pwndbg> got
GOT protection: Partial RELRO | GOT functions: 1
[0x404018] puts@GLIBC_2.2.5 -> 0x401030 ◂— endbr64

binary를 실행한 직후의 GOT 주소를 확인해보면 0x401030을 가리키고 있음(실제 puts 함수 주소가 아님)

 

1번째 puts 함수를 호출하는 부분(main+15)에 bp를 걸어 puts 함수을 step in 해보면 

pwndbg> b *main+15
pwndbg> c
pwndbg> si
   0x401040       <puts@plt>                        endbr64 
 ► 0x401044       <puts@plt+4>                      bnd jmp qword ptr [rip + 0x2fcd]     <0x401030>
    ↓
   0x401030                                         endbr64 
   0x401034                                         push   0
   0x401039                                         bnd jmp 0x401020                     <0x401020>
    ↓
   0x401020                                         push   qword ptr [rip + 0x2fe2]      <_GLOBAL_OFFSET_TABLE_+8>
   0x401026                                         bnd jmp qword ptr [rip + 0x2fe3]     <_dl_runtime_resolve_xsavec>
    ↓
   0x7ffff7fe7bc0 <_dl_runtime_resolve_xsavec>      endbr64 
   0x7ffff7fe7bc4 <_dl_runtime_resolve_xsavec+4>    push   rbx
   0x7ffff7fe7bc5 <_dl_runtime_resolve_xsavec+5>    mov    rbx, rsp
   0x7ffff7fe7bc8 <_dl_runtime_resolve_xsavec+8>    and    rsp, 0xffffffffffffffc0

puts@plt+4에서 앞서 확인한 0x401030으로 jump하는 것을 볼 수 있음

이후에는 _dl_runtime_resolve_xsavec 함수가 실행되는데, 해당 함수가 실행되면서 puts 함수의 실제 주소가 구해짐

_dl_runtime_resolve_xsavec 함수를 통해 구한 주소는 GOT table에 저장됨

 

pwndbg> finish
pwndbg> got
GOT protection: Partial RELRO | GOT functions: 1
[0x404018] puts@GLIBC_2.2.5 -> 0x7ffff7e46420 (puts) ◂— endbr64

GOTputs 함수의 실제 주소가 저장된 것을 확인할 수 있음


resolve된 후

1번째 puts 함수를 호출할 때 _dl_runtime_resolve_xsavec 함수를 통해 실제 puts 함수 주소를 구해 GOT에 저장했음

2번째 puts 함수를 호출할 때에는 1번째 puts 함수를 호출하며 구한 주소가 GOT에 저장되어 있으므로 바로 puts 함수를 실행할 수 있음

pwndbg> b *main+27
pwndbg> c
pwndbg> si
►  0x401040       <puts@plt>      endbr64 
   0x401044       <puts@plt+4>    bnd jmp qword ptr [rip + 0x2fcd]     <puts>
    ↓
   0x7ffff7e46420 <puts>          endbr64 
   0x7ffff7e46424 <puts+4>        push   r14
   0x7ffff7e46426 <puts+6>        push   r13
   0x7ffff7e46428 <puts+8>        push   r12
   0x7ffff7e4642a <puts+10>       mov    r12, rdi
   0x7ffff7e4642d <puts+13>       push   rbp
   0x7ffff7e4642e <puts+14>       push   rbx
   0x7ffff7e4642f <puts+15>       call   *ABS*+0x9f630@plt                <*ABS*+0x9f630@plt>
 
   0x7ffff7e46434 <puts+20>       mov    r13, qword ptr [rip + 0x167b0d]

PLT & GOT의 보안 취약점

PLT에서 GOT을 참조하여 실행 흐름을 옮길 때, GOT의 값을 검증하지 않음

앞선 실습에서 1번째 puts 함수를 호출하며 GOT에 저장한 puts 함수의 실제 주소를 변조할 수 있다면, 2번째 puts 함수를 호출할 때 puts 함수 대신 다른 코드가 실행되도록 할 수 있음(GOT Overwrite)

 

실습 코드를 약간 수정하여 /bin/sh를 호출할 수 있는 get_shell 함수를 삽입함

// Name: got.c
// Compile: gcc -o got got.c -no-pie

#include <stdio.h>

void get_shell(){
        system("/bin/sh");
}

int main() {
  puts("Resolving address of 'puts'.");
  puts("Get address from GOT");
}
pwndbg> info func
All defined functions:

Non-debugging symbols:
0x0000000000401000  _init
0x0000000000401050  puts@plt
0x0000000000401060  system@plt
0x0000000000401070  _start
0x00000000004010a0  _dl_relocate_static_pie
0x00000000004010b0  deregister_tm_clones
0x00000000004010e0  register_tm_clones
0x0000000000401120  __do_global_dtors_aux
0x0000000000401150  frame_dummy
0x0000000000401156  get_shell
0x0000000000401172  main
0x00000000004011a0  __libc_csu_init
0x0000000000401210  __libc_csu_fini
0x0000000000401218  _fini


pwndbg> disass puts
Dump of assembler code for function puts@plt:
   0x0000000000401050 <+0>:	endbr64 
   0x0000000000401054 <+4>:	bnd jmp QWORD PTR [rip+0x2fbd]        # 0x404018 <puts@got.plt>
   0x000000000040105b <+11>:	nop    DWORD PTR [rax+rax*1+0x0]
End of assembler dump.
pwndbg> b *main+27
Breakpoint 1 at 0x40118d
pwndbg> r
pwndbg> set *(unsigned long long*) 0x404018=0x401156
pwndbg> c
Continuing.
$ ls
got  got.c  Return_Address_Overwrite  ReturnToShellcode  ssp_000  ssp_001
$
  • gdb에서 값을 변경하고 싶을 때에는 set 명령을 이용할 수 있음
    • puts@got(0x404018)get_shell 함수 주소(0x401156)으로 변조하면 2번째 puts 함수를 호출하였을 때 /bin/sh 쉘이 출력되는 것을 확인할 수 있음

새롭게 알게 된 것

libc의 모든 함수들은 정해진 순서가 있으며, 외부 바이너리에서 함수를 호출하면 공유 라이브러리 내부의 순서를 우선시하여 index를 부여함

'Hacking Study > Pwnable' 카테고리의 다른 글

Static Link vs Dynamic Link  (0) 2023.03.02
Stack Canary  (2) 2023.03.01
dreamhack의 [Background: Library - Static Link vs. Dynamic Link]를 토대로 정리하였으며, 추가적으로 덧붙인 내용입니다.

 

Library란?

컴퓨터 시스템에서 프로그램들이 함수나 변수 등을 공유하여 사용할 수 있도록 하는 것
  • 대표적으로 printf, scanf, strlen, memcpy, malloc 등의 함수가 있음
  • 자주 사용되는 함수들의 정의를 묶어 하나의 라이브러리 파일로 만들고, 이를 여러 프로그램이 공유하여 사용할 수 있도록 지원하고 있음
  • Library를 사용하면 같은 함수를 반복적으로 정의하지 않아도 손쉽게 활용할 수 있어 코드 개발의 효율을 높임
    • 각 언어에서 범용적으로 많이 사용되는 함수들은 표준 라이브러리가 제작되어 있어 호출만 하면 사용할 수 있음
  • C의 표준 Library인 libc는 ubuntu에 기본으로 탑재되어 있으며, /lib/x86-64-linux-gnu/libc-2.27.so에 존재함

해당 경로에서 위와 같은 방법으로 찾아볼 수 있으나, 필자는 ubuntu 버전차로 libc-2.27.so는 존재하지 않음

 

C의 printf 함수

 

libc에 정의된 printf 함수의 source code는 다음과 같음

/* Copyright (C) 1991-2018 Free Software Foundation, Inc.
   This file is part of the GNU C Library.

   The GNU C Library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Lesser General Public
   License as published by the Free Software Foundation; either
   version 2.1 of the License, or (at your option) any later version.

   The GNU C Library is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Lesser General Public License for more details.

   You should have received a copy of the GNU Lesser General Public
   License along with the GNU C Library; if not, see
   <http://www.gnu.org/licenses/>.  */

#include <libioP.h>
#include <stdarg.h>
#include <stdio.h>

#undef printf

/* Write formatted output to stdout from the format string FORMAT.  */
/* VARARGS1 */
int
__printf (const char *format, ...)
{
  va_list arg;
  int done;

  va_start (arg, format);
  done = vfprintf (stdout, format, arg);
  va_end (arg);

  return done;
}

#undef _IO_printf
ldbl_strong_alias (__printf, printf);
/* This is for libg++.  */
ldbl_strong_alias (__printf, _IO_printf);

출처: https://github.com/lattera/glibc/blob/master/stdio-common/printf.c

 

 

만약 libraryprintf 함수가 정의되어 있지 않다면, printf("Hello, World")를 출력하고자 할 때 printf 함수의 원형을 함께 정의해주어야만 사용할 수 있음

#include <libioP.h>
#include <stdarg.h>
#include <stdio.h>

#undef printf

int
__printf (const char *format, ...)
{
  va_list arg;
  int done;

  va_start (arg, format);
  done = vfprintf (stdout, format, arg);
  va_end (arg);

  return done;
}

#undef _IO_printf
ldbl_strong_alias (__printf, printf);
/* This is for libg++.  */
ldbl_strong_alias (__printf, _IO_printf);

int main(){
	printf("Hello, World");
    return 0;
}

정확하진 않지만 대략적으로 이러한 형태로 사용해야 할 것임

사용하는 모든 함수에 대해 매번 정의하는 것은 매우 비효율적임

그렇기 때문에 자주 사용하는 함수들에 대해 미리 정의해둔 libc를 불러와 사용할 수 있으면 코드 개발에 있어 효율이 높아지게 되는 것!

 

💡 그렇다면 libc를 어떻게 연결해준다는 것인지에 대한 의문이 발생할 수 있음

Link란?

프로그램에서 어떤 라이브러리의 함수를 사용하고자 할 때, 호출된 함수와 실제 라이브러리 함수를 연결해주는 과정

 

리눅스에서 C source code는 전처리 → 컴파일 → 어셈블 과정을 거쳐 ELF형식을 갖춘 Object File로 번역됨

쉽게 말해, 인간의 언어를 컴퓨터에게 전달하기 위해서는 고급언어(인간 친화적인 언어)인 C, C++, Java 등의 언어로 작성한 소스코드를 0과 1로만 구성된 기계어로 번역하는 과정이 필요함

이를 변환해주는 과정을 컴파일이라고 지칭하며, 세부적으로 전처리 → 컴파일 → 어셈블 과정을 거침

출처: https://bpsecblog.wordpress.com/2016/03/07/about_got_plt_1/

 

✨ 고급 언어와 저급 언어

 

어셈블 예

// Name: hello-world.c
// Compile: gcc -o hello-world hello-world.c

#include <stdio.h>

int main() {
  puts("Hello, world!");
  return 0;
}

해당 코드는 

gcc -c hello-world.c -o hello-world.o

와 같은 방식으로 어셈블할 수 있음

 

Object File은 실행 가능한 형식을 갖추고 있지만, library 함수들의 정의가 어디에 존재하는지 알 수 없어 실행 불가함

// Path: /usr/include/stdio.h
...
/* Write a string, followed by a newline, to stdout.
   This function is a possible cancellation point and therefore not
   marked with __THROW.  */
extern int puts (const char *__s);
...

puts 함수에 대한 선언은 /usr/include/stdio.h에 정의되어 있음

그러나 puts 함수 내부 코드에 대해서는 정의되어 있지 않음

이와 관련된 정보들을 찾아 최종 실행 파일에 기록하는 것이 link 과정에서 일어나는 것임!

 

코드에 대해 완전히 컴파일하고, link 되기 전후 과정을 비교해보면 다음과 같음

$ gcc -o hello-world hello-world.c

$ readelf -s hello-world | grep puts
     2: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND puts@GLIBC_2.2.5 (2)
    46: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND puts@@GLIBC_2.2.5
    
$ ldd hello-world
        linux-vdso.so.1 (0x00007ffec3995000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fee37831000)
        /lib64/ld-linux-x86-64.so.2 (0x00007fee37e24000)

libc에 대해 source code와 함께 컴파일하지 않았음에도 불구하고 libc에서 puts 함수에 대해 탐색할 수 있었던 것은, libc 파일이 존재하는 /lib/x86_64-linux-gnu/표준 library 경로에 포함되어 있기 때문임

gcc 컴파일러는 source code를 컴파일할 때 표준 library 경로에 있는 모든 library File들을 탐색함

이렇게 Link 과정을 거치고 나면 binary에서 puts 함수를 호출할 때, puts 함수가 정의되어 있는 libc에서 puts 함수의 코드를 찾아 실행하게 됨

🔍 요약
Link/Linking은 컴파일 이후 프로그램을 실행하기 이전에, 프로그램이 사용하는 다른 프로그램이나 library를 가져와 연결하는 과정

표준 libc로 지정한 파일 이외에도 사용자가 작성한/보유한 파일에 대해 직접 linking 해줄 수도 있음

실행 흐름 정리)
binary에서 puts 함수 호출 → libc에서 puts 함수 코드 찾아 실행 → binary에서 puts 함수의 다음 코드 실행
참고) 표준 Library 경로 탐색 명령
$ ld --verbose | grep SEARCH_DIR | tr -s ' ;' '\n'

SEARCH_DIR("=/usr/local/lib/x86_64-linux-gnu")
SEARCH_DIR("=/lib/x86_64-linux-gnu")
SEARCH_DIR("=/usr/lib/x86_64-linux-gnu")
SEARCH_DIR("=/usr/lib/x86_64-linux-gnu64")
SEARCH_DIR("=/usr/local/lib64")
SEARCH_DIR("=/lib64")
SEARCH_DIR("=/usr/lib64")
SEARCH_DIR("=/usr/local/lib")
SEARCH_DIR("=/lib")
SEARCH_DIR("=/usr/lib")
SEARCH_DIR("=/usr/x86_64-linux-gnu/lib64")
SEARCH_DIR("=/usr/x86_64-linux-gnu/lib")​

Link 종류

Library동적 library, 정적 library로 구분되며, 동적 librarylink하는 것을 Dynamic Linking, 정적 librarylink하는 것을 Static Link라고 부름

 

Dynamic Link

동적 link된 binary를 실행하면 동적 library가 프로세스의 메모리에 mapping됨

실행 중 library의 함수를 호출하면, mapping된 library에서 호출할 함수의 주소를 찾고 해당 함수를 실행함

동적 library공유 library라고도 부름

 

Dynamic Compile

$ gcc -o dynamic hello-world.c -no-pie

file 명령어를 통해 확인해보면 dynamically linked로 연결된 것을 확인할 수 있음

 

Static Link

binary에 정적 library의 모든 함수가 포함됨

함수를 호출할 때 library를 참조하는 것이 아니라 binary에 원래 존재하는 함수를 호출하는 것처럼 호출할 수 있음

Library에서 원하는 함수를 찾지 않아도 되지만 여러 binary에서 library를 사용하면 해당 library의 복제가 여러 번 이뤄져 많은 용량을 요구하게 됨

즉, library와 object file을 모두 포함하여 하나의 실행파일이 만들어짐

🧨 Static Link 시, 컴파일 옵션에 따라 include한 헤더의 함수가 모두 포함될 수도 그렇지 않을 수도 있음!

 

Static Compile

$ gcc -o static hello-world.c -static

file 명령어를 통해 확인해보면 statically linked로 연결된 것을 확인할 수 있음

 

Dynamic Link와 Static Link 비교

1) 용량

  • Dynamic Link로 생성한 dynamic binary에 비해 Static Link로 생성한 static binary의 용량이 훨씬 크다는 것을 알 수 있음(library를 모두 포함하여 컴파일하였기 때문)

 

2) 호출 방법

 //static
 
 main:
  push   rbp
  mov    rbp,rsp
  lea    rdi,[rip+0x915dc] # 0x492144
  call   0x410230 <puts>
  mov    eax,0x0
  pop    rbp
  ret
//dynamic

main: 
 push   rbp
 mov    rbp,rsp
 lea    rdi,[rip+0x92] # 0x400584
 call   0x4003f0 <puts@plt>
 mov    eax,0x0
 pop    rbp
 ret
  • static에서는 puts 함수를 직접적으로 호출하고 있음
  • dynamic에서는 puts의 plt 주소를 호출함 → library에서 puts 함수를 찾아야하기 때문
    • plt는 library에서 puts 함수를 찾기 위해 필요한 테이블임

 

한 눈에 보는 Dynamic Link와 Static Link

출처: https://bpsecblog.wordpress.com/2016/03/07/about_got_plt_1/

 

'Hacking Study > Pwnable' 카테고리의 다른 글

PLT & GOT  (0) 2023.03.02
Stack Canary  (2) 2023.03.01
이론은 [Dreamhack - Mitigation: Stack Canary] 부분을 정리한 뒤 추가적으로 덧붙였습니다.

 

Stack Canary

  • 함수의 프롤로그에서 스택 버퍼와 반환 주소 사이에 임의의 값을 삽입하고, 함수의 에필로그에서 해당 값의 변조를 확인하는 보호 기법
  • 카나리 값의 변조가 확인되면 프로세스는 강제로 종료됨
  • 스택 버퍼 오버플로우로 반환 주소를 덮으려면 반드시 카나리를 먼저 덮어야 함
    • 카나리 값을 모르는 공격자는 반환 주소를 덮을 때 카나리 값을 변조하게 되고, 에필로그에서 변조가 확인되어 공격자는 실행 흐름을 획득하지 못함

 

🦜 카나리 이름의 유래 (Canary in a Coal Mine)
19세기, 20세기에는 일산화탄소 농도의 측정 기술이 부족했고, 탄광에서 유출된 일산화탄소에 광부가 중독사하는 사건이 빈번하게 발생했음. 카나리아라는 새는 유독가스에 민감해 사람이 중독되기 전에 먼저 반응하여 죽기 때문에, 누출을 사전에 인지 가능했음
이로 인해 카나리아는 “위험을 알려주는 새”라는 상징적 의미를 갖게 됨
소프트웨어를 출시하거나 업데이트할 때, 베타 테스트 용도로 공개하는 버전을 카나리 버전이라고 부르는 것도 이런 의미가 반영된 것
카나리 보호 기법도 반환 주소가 덮인 것을 알려준다는 의미에서 “카나리”로 이름 붙여짐
카나리아 새 - 이미지 출처: https://itwiki.kr/w/%EC%B9%B4%EB%82%98%EB%A6%AC

 

 

컴파일 시 카나리 옵션 적용하기

  • gcc 컴파일 시 옵션을 주지 않으면 기본적으로 canary가 적용됨

  • canary 옵션을 빼고 싶다면 -fno-stack-protector 옵션을 사용하면 됨

 

카나리 활성화 여부에 따른 error 발생 차이

실습 바이너리는 [Dreamhack - Return to Shellcode]를 대상으로 수행하였습니다.
  • canary 적용 → stack smashing detected

임의의 값을 지정된 버퍼보다 훨씬 많은 값을 주었을 때 stack smashing detected라는 error가 발생함 -> canary가 존재함을 알 수 있음

  • canary 미적용 → Segmentation fault

canary가 적용되지 않은 경우 버퍼 크기 보다 많은 값을 입력했을 때 Segmentation fault라는 error가 발생함

 

GDB에서 canary가 적용된 것을 확인해보자

push   rbp
mov    rbp,rsp
sub    rsp,0x10
mov    rax,QWORD PTR fs:0x28
mov    QWORD PTR [rbp-0x8],rax
xor    eax,eax
lea    rax,[rbp-0x10]
lea    rax,[rbp-0x8]
mov    edx,0x20
mov    rsi,rax
mov    edi,0x0
call   read@plt
mov    eax,0x0
mov    rcx,QWORD PTR [rbp-0x8]
xor    rcx,QWORD PTR fs:0x28
je     0x6f0 <main+70>
call   __stack_chk_fail@plt
leave
ret

 

💎 확인해야 하는 코드 1

mov    rax,QWORD PTR fs:0x28
mov    QWORD PTR [rbp-0x8],rax

1. fs:0x28 → 데이터를 읽어 rax에 저장함

  • fs: 세그먼트 레지스터의 일종으로 리눅스는 프로세스가 시작될 때 fs:0x28에 랜덤 값을 저장함
💡 cs, ds, es는 CPU가 사용 목적을 명시한 레지스터인 반면, fs와 gs는 목적이 정해지지 않아 운영체제가 임의로 사용할 수 있는 레지스터
  • 리눅스는 fs를 **Thread Local Storage(TLS)**를 가리키는 포인터로 사용
    • TLS에는 카나리를 비롯하여 프로세스 실행에 필요한 여러 데이터가 저장됨

1-1. mov    rax,QWORD PTR fs:0x28

  • 결과적으로 rax에는 첫 1byte가 null-byte인 8byte 랜덤 데이터가 저장됨
pwndbg> print /a $rax
$1 = 0xf80f605895da3c00

2. mov    QWORD PTR [rbp-0x8],rax

  • rax에 저장된 canary를 rbp-0x8에 저장(stack memory 상에 위치하게 됨)

 

💎 확인해야 하는 코드 2

mov    rcx,QWORD PTR [rbp-0x8]
xor    rcx,QWORD PTR fs:0x28
je     0x6f0 <main+70>
call   __stack_chk_fail@plt

1. mov    rcx,QWORD PTR [rbp-0x8]

  • rbp-8에 저장되어 있는 canary 값을 rcx에 저장함

2. xor    rcx,QWORD PTR fs:0x28

  • rcx에 저장된 canary 값과 기존에 fs:0x28에 저장된 canary 값을 xor 연산
  • 두 값이 동일하면 연산 결과가 0이 되면서 je 조건을 만족하여 main 함수가 정상적으로 반환됨
  • 그러나 두 값이 동일하지 않으면 __stack_chk_fail이 호출되면서 프로그램이 강제로 종료됨
가장 처음 생성하였던 fs:0x28의 canary와 스택에 저장된 canary(rbp-0x8)가 같은지 비교하는 것
만약 BOF가 발생하였다면 canary 값을 임의의 값으로 덮어쓰게 될 것이고, 이는 스택에 저장된 canary 값을 변조하게 됨
이로 인해 fs:0x28의 canary와 xor 연산하게 되면 불일치하여 1이 반환될 것! → stack smashing detected error 발생
💡xor 연산
bit 1 bit 2 result
0 0 0
0 1 1
1 0 1
1 1 0
같은 bit일 때 0을 반환, 다를 때 1을 반환 함
canary 또한 두 값이 동일하다면 연산하는 bit 모두 동일하므로 결과적으로 0이 반환되는 것!

 

카나리 생성 과정

  • 카나리 값은 프로세스가 시작될 때 TLS에 전역 변수로 저장되고 각 함수마다 프롤로그와 에필로그에서 해당 값을 참조함

 

TLS의 주소 파악

  • fsTLS를 가리키므로 fs 값을 알면 TLS의 주소를 알 수 있음
    • BUT 리눅스에서 fs 값은 특정 시스템 콜을 사용해야만 조회하거나 설정할 수 있음(info register fs, print $fs 등으로 알 수 없다는 말!)
  • fs의 값을 설정할 때 호출되는 arch_prctl(int code, unsigned long addr) 시스템 콜에 bp 걸어 확인할 수 있음
    • arch_prctl(ARCH_SET_FS, addr)의 형태로 호출하면 fs의 값은 addr로 설정됨
    $ gdb -q ./canary
    pwndbg> catch syscall arch_prctl
    Catchpoint 1 (syscall 'arch_prctl' [158])
    pwndbg> run
    
    Catchpoint 1 (call to syscall arch_prctl), 0x00007ffff7dd6024 in init_tls () at rtld.c:740
    740	rtld.c: No such file or directory.
     ► 0x7ffff7dd4024 <init_tls+276>    test   eax, eax
       0x7ffff7dd4026 <init_tls+278>    je     init_tls+321 <init_tls+321>
       0x7ffff7dd4028 <init_tls+280>    lea    rbx, qword ptr [rip + 0x22721]
    pwndbg> info register $rdi
    rdi            0x1002   4098          // ARCH_SET_FS = 0x1002
    pwndbg> info register $rsi
    rsi            0x7ffff7fdb4c0   140737354032320 
    pwndbg> x/gx 0x7ffff7fdb4c0+0x28
    0x7ffff7fdb4e8:	0x0000000000000000
    
💡gdb catch(catchpoint)
특정 이벤트가 발생했을 때 프로세스를 중지함

 

  • catchpoint에 도달했을 때, rdi에 저장된 0x1002ARCH_SET_FS의 상숫값임
  • rsi 값이 0x7ffff7fdb4c0이므로 이 프로세스는 TLS를 0x7ffff7fdb4c0에 저장할 것이며, fs는 이를 가리키게 될 것
  • 카나리가 저장될 fs+0x28(0x7ffff7fdb4c0+0x28)의 값을 보면, 아직 어떠한 값도 설정되어 있지 않음

 

canary 값 설정

  • TLS+0x28에 값을 쓸 때 wathpoint 설정
    • security_init 함수에서 프로세스가 멈춤
💡gdb watch(watchpoint)
특정 주소에 저장된 값이 변경되면 프로세스 중지함
pwndbg> watch *(0x7ffff7fdb4c0+0x28)
Hardware watchpoint 4: *(0x7ffff7fdb4c0+0x28)

pwndbg> continue
Continuing.

Hardware watchpoint 4: *(0x7ffff7fdb4c0+0x28)

Old value = 0
New value = -1942582016
security_init () at rtld.c:807
807	in rtld.c

pwndbg> x/gx 0x7ffff7fdb4c0+0x28
0x7ffff7fdb4e8:	0x2f35207b8c368d00

TLS+0x28의 값을 조회하면 canary 값이 0x2f35207b8c368d00으로 설정된 것을 확인할 수 있음

 

  • 해당 값이 실제 main 함수에서 사용하는 canary 값인지 확인
pwndbg> b *main
Breakpoint 3 at 0x5555555546ae

Breakpoint 3, 0x00005555555546ae in main ()
pwndbg> x/10i $rip
 ► 0x5555555546ae <main+4>:	    sub    rsp,0x10
   0x5555555546b2 <main+8>:	    mov    rax,QWORD PTR fs:0x28
   0x5555555546bb <main+17>:	mov    QWORD PTR [rbp-0x8],rax
   0x5555555546bf <main+21>:	xor    eax,eax
   0x5555555546c1 <main+23>:	lea    rax,[rbp-0x10]
   0x5555555546c5 <main+27>:	mov    edx,0x20
   0x5555555546ca <main+32>:	mov    rsi,rax
   0x5555555546cd <main+35>:	mov    edi,0x0
   0x5555555546d2 <main+40>:	call   0x555555554580 <read@plt>
   0x5555555546d7 <main+45>:	mov    eax,0x0
pwndbg> ni
0x00005555555546b2 in main ()
pwndbg> ni
0x00005555555546bb in main ()
pwndbg> i r $rax
rax            0x2f35207b8c368d00	3401660808553729280

mov rax, QWORD PTR fs:0x28 부분 실행 후 rax 값을 확인해보면 security_init에서 설정한 값과 같은 것을 알 수 있음

 

카나리 우회

1. 무차별 대입(Brute Force)

  • x64 아키텍처에서는 8byte의 canary가 생성됨
    • Brute Force로 최대 256^7번 연산이 필요함
  • x86 아키텍처에서는 4byte의 canary가 생성됨
    • Brute Force로 최대 256^3번의 연산이 필요함
  • canary에는 null-byte가 포함되어, 실제로는 7byte, 3byte의 random한 값이 포함됨!

→ 무차별 대입으로 알아내는 것은 현실적으로 어려움

 

 

2. TLS 접근

  • canary는 TLS에 전역변수로 저장됨
    • 매 함수마다 이를 참조해서 사용함!
    • TLS 주소는 매 실행마다 바뀌지만 실행 중 TLS 주소를 알 수 있고, 임의 주소에 대한 읽기 또는 쓰기가 가능할 경우 TLS에 설정된 canary 값을 읽거나 임의의 값으로 조작할 수 있음

→ stack BOF를 수행할 때 알아낸 canary 값 또는, 조작한 canary 값으로 stack canary를 덮으면 함수 에필로그에 있는 canary 검사를 우회할 수 있음!

 

실습

// Name: bypass_canary.c
// Compile: gcc -o bypass_canary bypass_canary.c
#include <stdio.h>
#include <unistd.h>

int main() {
  char memo[8];
  char name[8];
  
  printf("name : ");
  read(0, name, 64);
  printf("hello %s\n", name);
  
  printf("memo : ");
  read(0, memo, 64);
  printf("memo %s\n", memo);
  
  return 0;
}
  • memo, name은 각각 8bytes씩 할당됨
  • read 함수를 통해 name, memo에 64bytes씩 입력할 수 있음 → 주어진 buffer 크기보다 더 많은 값을 입력할 수 있으므로 BOF 취약점 발생
  • printf 함수를 통해 입력한 name과 memo에 대한 값을 출력해줌

stack 구조

💡printf 함수
printf 함수는 null-byte가 오기 직전까지 출력해줌
입력 값의 가장 마지막은 null-byte가 위치하여 메모리 상에서 값에 대한 구분을 하게 됨
즉, memo와 name에 대해 입력하게 된다면 각각의 마지막 byte는 null로서 구분됨
그러나 이때, 마지막 byte를 null-byte가 아닌 임의의 값으로 채워준다면 지정된 buffer 이후의 값도 출력할 수 있음
  • 예를 들어, name에 임의의 값(다수의 a)를 입력한 뒤, memo에 8bytes를 꽉채워 입력하게 되면 null-byte를 덮어쓰게 됨
  • printf 함수는 null-byte가 올 때까지의 모든 것을 출력해주므로, memo 뒤에 위치한 name에 있는 값까지 출력하게 됨

memo에 대한 값을 print하는 부분에서 name 값까지 leak된 것을 확인할 수 있음

 

💡name 직후에 존재하는 canary에 대해서도 이와 같은 방법으로 leak할 수 있음
그러나 여기서는 name에 대한 8byte만 채우면 안됨
canary의 첫 번째 byte가 null-byte이므로 name[8]+canary[1] 만큼의 dummy 값을 줘야 printf 함수를 통해 canary 값을 leak할 수 있음

9byte의 입력 값을 주었을 때 leak된 canary

  • shell에서 보았을 때 canary 값이 이상하게 깨져서 보이는데, 이는 canary가 갖는 hex 값에 대해 ascii 문자로 치환할 수 있는 것이 없기 때문

  • 위의 ascii 코드표(ASCII Table)에 matching되는 hex에 대해서만 치환 가능 

 

상세한 canary leak과 해당 과정을 통해 shell을 획득하는 것에 대해서는 [dreamhack - ReturnToShellcode]
, [dreamhack - ssp_001], [dreamhack - ssp_000] 문제 풀이를 통해 확인할 수 있습니다.

'Hacking Study > Pwnable' 카테고리의 다른 글

PLT & GOT  (0) 2023.03.02
Static Link vs Dynamic Link  (0) 2023.03.02

+ Recent posts