---
# System prepended metadata

title: Reversing.kr Write-up 1
tags: [' Reversing', CTF]

---

---
title: Reversing.kr Write-up 1
description: 一些 Reversing.kr 篇幅不長的 Write-up 集中地
tags: CTF, Reversing
lang: zh_tw
---

# 🚩 Reversing.kr Write-up 1
[TOC]

## Easy_CrackMe
### 👀 Analyze the decompiled code
靜態分析嘛，先想辦法到比較關鍵點的 code
先執行看看

![](https://i.imgur.com/SZmil9H.png)

ok 有呼叫一個視窗出來講 Incorrect Password

這次用 Ghidra 這工具，跟它培養一下感情
![](https://i.imgur.com/jTjJkit.png)

從旁邊的 Symbol Tree 找到 MessageBoxA 這個創造視窗的 API
對它右鍵 -> Show References to
找到哪邊有 call 到它
就找到了這邊

![](https://i.imgur.com/XsHrt7I.png)
尾巴就看到了 Congratulation 跟 Incorrect Password 兩種結局
那要怎樣才能進到好結局勒

從 Line 27 可以知道 cStack99 要是 a
從 Line 49 知道 cStack100 要是 E
從 Line 28 知道 acStack98 兩個字要是 5y
![](https://i.imgur.com/i1zkVf7.png)
這樣就組出 Ea5y 了

在 Line 29 ~ 47 的 if 中定義
pbVar4 是 0x0040606c
![](https://i.imgur.com/clPrO0h.png)
pbVar2 是 abStack96
這兩個字串會一直比到結束，一次比 2 bytes，都需一樣
所以知道 abStack96 必須是 R3versing

合起來整個從 cStack100 開始的字串就是

就是答案

## Easy_KeygenMe
這支程式 run 一下
![](https://i.imgur.com/VhpjZKO.png)

會要求輸入 Name 和 Serial
題目的 README 寫著要找到對應 Serial 為 **5B134977135E7D13** 的 Name

### 👀 Analyze the decompiled code
OK，那先從找哪邊用到`Input Name:`跟`Input Serial:`這兩個字串開始

用 Ghidra 打開，跑一下 Auto Analyze

![](https://i.imgur.com/9BSyP4X.png)
主要要選到 ASCII Strings

跑完分析後，接著按一下 Window -> Defined Strings 
搜尋字串 `Input Name`
![](https://i.imgur.com/gbcbCRq.png)
對 00408060 辣個 Address 點兩下左鍵

![](https://i.imgur.com/WTaPosD.png)
再對 code 裡面的 00408060 辣個 Address 點右鍵 -> References
-> Show References to Address

找到哪邊有用到這個字串ㄌ
就在 0040102e

![](https://i.imgur.com/FJyFNVE.png)
一樣對 Address 左鍵點兩下可以快速移動到該 Address

旁邊就有 Decompile 的 code 可以參考
嗯~ Ghidra 這免費分析工具不錯用

![](https://i.imgur.com/TF2rRPG.png)
~~FUN_print FUN_scan 是我改名過後的~~
可以看到 Line 87 ~ 101 的 do while 結束後
如果中間完全沒直接跳到 LAB_00401113，老老實實的執行完迴圈
會因為 Line 102 的 code，進入 Line 105 ~ 106 輸出 Correct
否則就會輸出 Wrong

所以**如何才會輸出 Correct** 這個問題就變成在問
**要怎樣才能老老實實的執行完迴圈 ?**
Line 90 中， bVar2 的值其實是 \*pbVar3
所以 Line 90 其實在比對 pbVar3 跟 pbVar7 這兩個地址中的值

- 如果不一樣
    - 若 bVar10 是 1 (true)，最終 iVar4 會是 0 - 1 = -1
        - 最終輸出 Wrong
    - 若 bVar10 是 0 (false)，最終 iVar4 會是 1 - 0 = 1
        - 最終輸出 Wrong
            
    說到底，進到這裡就表示最終輸出都是 Wrong

所以輸出 Correct 的條件之一是 **\*pbVar3 跟 \*pbVar7 需相同**

接著看到 Line 95，比對到 \*pbVar3 是 0 就結束比對，輸出 Correct

不是 0 的話，後面就得還要繼續比對
Line 96 ~ 98 根本是 Line 88 ~ 94 的翻版
只是比較對象是 \*pbVar3\[1\] 跟 \*pbVar7\[1\]

Line 99 ~ 100 將兩個地址 pbVar3 pbVar7 都直接加 2

---

總結這一個 Block (Line 87 的 do while ~ 最後) 的 code 在幹嘛
翻譯為人類聽得懂的話，就是

**比對 pbVar3 pbVar7 這兩個地址上的字串，一次比對兩個字
都一樣就輸出 Correct，反之輸出 Wrong**

---

繼續往上看

Line 85 ~ 86 寫
pbVar7 為 abStack176
pbVar3 為 abStack276

所以我說 abStack176 abStack276 這兩個地址上的字串是啥勒?

---

先來看看 FUN_scan 是啥好了 owo

![](https://i.imgur.com/MWqNTV8.png)
call 了 FUN_scan("%s", ESP + 0x10)

![](https://i.imgur.com/eMFoBK0.png)
FUN_scan(param1, param2) 
又繼續 call 了 FUN_00401c8e(00408090、param1、&param2)
也就是 FUN_00401c8e(00408090、"%s"、&param2)

---

進到 FUN_00401c8e 我傻眼
781 行 code

不過還是耐住性子看一下

整個 code 被一個超大 do {} while(true) 包住

![](https://i.imgur.com/wcDzeVw.png)

首先第一個 block 目光來到 Line 70 ~ 79

bVar1 在 Line 63 可以看到，是第二個參數，也就是 "%s"
~~在此我有不祥的預感，該不會這裡實作了一個簡單的 scanf 吧~~
如果 bVar1 等於 0，就會進這判斷式，不過因為我們ㄉ bVar1 不是 0
就先不看裡面做什麼了 ~~反正不會進去麻~~

接著第二個 block 看到 Line 80 ~ 90
比較 \*(int \*)0x408680 裡的值是否 < 2
切到 0x408680 看到是 0x00000001
所以一開始會執行 Line 81 ~ 82 的 code

this_02 在 Line 67 定義為 0x408468，而 \*0x408468 為 0x408472
而 bVar1 為 \*param_2，單位是 1 byte，所以這邊 bVar1 會是 0x25 也就是 `%` 的 ASCII code

從地址 (0x408472 + 0x25 \* 2) 取一個 byte 出來並且 and 8
這就是 uVar4 !! (好累 汗顏@@)

---

好到這邊 我已經不想靜態分析了 XD
直接動態看一下，搞不好還比較簡單

### 💩 Dynamically Analyze
雖然說是動態分析，但若在靜態分析過後大概知道關鍵點是啥會更好
另外一點就是，Decompiler 只能參考，反編譯回去時可能跟原意有些許差距

好，現在還不知道 FUN_print 跟 FUN_scan 的作用
先在他們頭上設斷點

![](https://i.imgur.com/3qN4H80.png)

來到 Call FUN_print 前

![](https://i.imgur.com/ybshjAQ.png)

按一下 F8 步過

![](https://i.imgur.com/StIa0U9.png)
可以發現 Terminal 輸出文字ㄌ
所以大膽猜測，FUN_print 就是輸出 Stack 中第一個 pointer 所指向的字串

---

再來看看 FUN_scan
來到 Call FUN_scan 之前
![](https://i.imgur.com/D9Wfeb1.png)

按一下 F8 步過

![](https://i.imgur.com/nuc92HK.png)
發現 Terminal 可輸入東西

輸入進去後
![](https://i.imgur.com/2yS0Sg4.png)
很像 scanf(format, param1, param2 ...)
Stack 中第一個參數是 \"%s\"
第二個參數是 0x0018FE20
可以看到右下角 Stack
輸入字串被存到 0x0018FE20 了

---

那後面的邏輯是啥勒 ?
還是參考一下 Decompiler

![](https://i.imgur.com/NwKIqJx.png)
剛剛下的斷點分別是 Line 46, 47
所以接下來會執行的 code 是從 Line 48 開始

首先看到 Line 52 ~ 57
就是在算 pcVar8 所指的字串的長度
長度會存到 \~uVar5
Line 58 的條件式形同 \~uVar5 > 1
再來 Line 59 ~ 74的 do while 中
第一個區塊是 Line 60 ~ 62 的 if
配合 Line 50、66，讓 iVar6 一直循環 0 1 2 0 1 2 ...
if 過了之後 call FUN_00401150
這個 function 不知道在幹嘛，就很適合下斷點看看

Line 49、64 定義 iVar4 從 0 開始每 loop 一次就 ++ 一次
Line 68 ~ 73 又在算一次字串長度
最後 Line 74 目的是要把字串整個 loop 過一遍

---

好，來下斷點
斷在要 call FUN_00401150 之前

不過下斷點時，發現了一件在 decompiler 沒發現的事

![](https://i.imgur.com/Tyeqk3W.png)

0x0040107A 對應 Line 60 ~ 62 的 if
但是，but，西咖喜
0x0040107E 的 movsx ecx ... 
到
0x00401088 的 xor ecx, edx
好像沒在 decompiler 中有對應的 code ?!

那就先動態分析看看這邊在幹嘛

新設一個斷點在 0x0040107E 的 movsx ecx, ...
並且執行到它

![](https://i.imgur.com/wVEMBql.png)

esp + esi + C 此時等於 0x0018FE1C，值是 0x10
注意到這邊，esi 會循環 0 1 2 0 1 2 ...
所以 \[esp + esi + C\] 的值會循環 10 20 30 10 20 30 ...

在來 esp + ebp + 10 此時等於 0x0018FE20，也就是輸入字串

所以輸入的字串，會跟 0x10 0x20 0x30 這把 key xor
然後 call 進辣個神秘 function FUN_00401150

---

再來執行到 call FUN_00401150 之前
![](https://i.imgur.com/fPDcW6e.png)
可以看到 Stack 中
第一跟第三個參數一樣，為0x0018FE84
![](https://i.imgur.com/y4QvWhn.png)
那邊都是 0
第二個參數是一個像是 format 的東西 \"\%s\%02x\"
第四個參數是剛剛 xor 完的產物 0x71

按一下 F8 步過

![](https://i.imgur.com/140PZrG.png)
歐歐歐歐歐

![](https://i.imgur.com/09X2sjx.png)
剛剛 xor 的東西存來這了，而且是把 0x71 轉成字串 "71" 存起來

---

我們看看這個 do while 進到第二圈
並且再度停在 call FUN_00401150 之前
![](https://i.imgur.com/g8pjScc.png)
Stack 中的參數第一二三個參數依舊沒變
第四個參數也是 0x61 (a 的 ascii code) 跟 0x20 xor 的結果 0x41

按一下 F8 步過

![](https://i.imgur.com/BWTl1r6.png)

看看 0x0018FE84
![](https://i.imgur.com/qlGkyun.png)
把 xor 的產物 0x41 轉成字串 "41" 黏在字串後面了

---

整個 do while 都執行完
可以斷點斷在 0x004010B6
![](https://i.imgur.com/7W2SI1o.png)

看看 0x0018FE84
![](https://i.imgur.com/UbxHVby.png)
的確就是輸入字串 aaaabbbbccccdddd 跟 0x10 0x20 0x30 依序下去 xor 的產物轉成字串

---

再來設斷點在輸入 serial

![](https://i.imgur.com/eunWECS.png)

按下去 F8 

輸入
![](https://i.imgur.com/hPC1LT0.png)
![](https://i.imgur.com/0YU8L5m.png)

最後可以看到是前一 part 有分析出來的比較字串的部分
兩個字串的頭分別是剛剛輸入的 serial
跟 0x0018FE84

### 🚩 Got it
到目前為止已經知道怎解了
題目的 serial 是 **5B134977135E7D13**
就只要依序 xor 回去就好了

## Easy_UnpackMe
### 🤔 Pack Unpack
~~完全不知道是啥的可以查一下 `UPX`~~
~~Pack 中文翻加殼~~
~~Unpack 為脫殼~~
~~後面加 er 就變加殼器/脫殼器~~

---

我們先講講 **流程** :

假設原本我們的程式是 A
Packer 會把程式給**壓縮**起來，變成 B
並且把程式一開始的進入點改成一段**解壓縮**的 code，這裡用 C 來表示

關於程式進入點
Windows exe 可以 google `PE Header`
Linux elf 則可以 google `ELF Header`

| 程式名稱 | Binary 實際結構 |
| -------- | -------- |
| 原本程式    | A     |
| 加殼後的程式 | C, B |
運行時，會先執行**解壓縮**的code，將程式變回原來的樣子
| 程式名稱 | Binary 實際結構 |
| -------- | -------- |
| 執行完解壓縮    | C, A    |
解壓縮完後，JMP 到原本程式 A 執行原本要做的事情

---

**為啥要 Pack ?**

1. 反防毒:
    首先先問問 Anti-Virus 怎麼運作的 ? ~~雖然我也不是很了解，但我猜~~
    有一種方式是看有沒有特定的 pattern 出現
    比如說某些 pattern 就是開後門的 code 的長相
    
    那 Packer 壓縮原本的程式後，整個 pattern 就被打散了，達到反防毒的目的
    
2. 反逆向:
    好饒舌，反逆向
    
    原本沒 Pack 的程式，裡面的 OPcode 形同裸體，有心的人必能事成將它的邏輯搞懂
    Pack 後的程式，逆向攻城屍得先想辦法將它 Unpack，Unpack 不出來就連逆都不用逆
    
3. 壓縮:
    Packer 不只形同加密般把原本程式變成亂碼，還可以將 size 壓縮變小
    
### 👀 So, how to unpack ?
- 第一種方法
    看有沒有別人寫好的工具
    不過你也得先知道對應的 Packer 是什麼，才能找 Unpacker

    PEiD 就是個 Packer Detector 查殼器，自己去下載ㄅ

    不過它也不是萬用的，有些殼是程式創作者自己寫的，這種 Custom Packer 就查不到了

    ![](https://i.imgur.com/5iW8iSw.png)
    像是這題就查不到


- 第二種方法:
    用 x32/x64dbg 執行到真正的進入點
    套用前章節的說法
    
    > 運行時，會先執行**解壓縮**的code，將程式變回原來的樣子
    
    | 程式名稱 | Binary 實際結構 |
    | -------- | -------- |
    | 執行完解壓縮    | C, A    |
    
    一直逐步執行直到真正的進入點
    (所謂真正的進入點，就是進入 A 的點)
    
    此時程式都解壓縮回真正的樣貌了
    再把整個程式從 Memory dump 出來，並且將 Header 裡的進入點修改到真正的進入點
    就脫殼完成

### 😐 Entry Point, but not OEP

這題呢，來示範第二個方法

首先用 Ghidra 打開程式，看看 PE Header，來實際算一次進入點在哪
參考 PE Header 架構圖 
![](https://upload.wikimedia.org/wikipedia/commons/1/1b/Portable_Executable_32_bit_Structure_in_SVG_fixed.svg)

好像很長很可怕，但實際上要看的只有 
- offset 0x28 的 Address Of Entry Point
- offset 0x34 的 Image Base

兩者相加，就是 Entry Point

看看 Ghidra 畫面
![](https://i.imgur.com/ut2KVBa.png)
最前面這部分是 DOS Header
0x3c 的地方表示 Pointer to PE Header
看到 0x3c 上面的值是 0xd8
移駕到 0xd8 看一下
對著有地址的這個視窗按 G，並輸入 0x4000d8 就可以快速移動

![](https://i.imgur.com/mrcHeO9.png)

OK 我們要看的地方是
- offset 0x28 的 Address Of Entry Point
- offset 0x34 的 Image Base

兩個地方分別加上 offset 0xd8
也就是 0x100 跟 0x10c
![](https://i.imgur.com/Z7lTAcF.png)
![](https://i.imgur.com/iV79Sdg.png)

注意 Little-endian
所以這兩個值分別是
- 0x00a04b: Address Of Entry Point
- 0x400000: Image Base

相加就是 0x40a04b

看看 0x40a04b 的 code
![](https://i.imgur.com/VfUy1eF.png)

Ghidra 很貼心的在上面用 entry(void) 命名這段區間的 code

### 🤘 OEP !!
不過剛剛算的那個不是真的 OEP(Original-Entry-Point)
蛤，你問我怎麼知道 ? ~~因為 0040a04b 不是 FLAG 啊~~
那那那麼，0x40a04b 這個地址的 code 在幹嘛???
動態分析看看好了，丟到 x32dbg

![](https://i.imgur.com/uLTnwWP.png)
剛開起來就自動停在 0x40a04b 了
因為 x32dbg 會很貼心自動在 entry 下一個斷點
你可能會說: 欸欸乾 剛剛entry**算心酸**的喔
沒有啦~ 想說，帶你了解一下 entry 真正是怎麼算的麻~~

好，回正題，這邊的 code 我是沒有好好的 reverse 完
你可以好好的 reverse 這邊的 code 當練習
但我看到一堆 xor，我猜這邊就是在做前面說的**解壓縮**的步驟
只是如果只是 xor，那就不能說是**解壓縮**，而是**解密**
anyway，這一段 code 
我猜就是將 Packed 程式 B 還原回原本程式 A 的過程

那麼，最後要一個 JMP to A 的指令吧 ?

把這段 code 一直往下拉，拉阿拉....
![](https://i.imgur.com/4aJh6lg.png)

看來很可疑的 JMP，斷點設在辣邊，然後看看會跳到哪邊

噢噢跳到了這裡
![](https://i.imgur.com/xsk9COI.png)
(碼掉了，自己的 flag 自己找)
我們為了方便下面行文，辣個 OEP 我們就說是:
**004011XX** 

基本上到這裡，這題就結束了，不過
你不覺得很好奇嗎
1. 那原本沒執行 C 時，**004011XX** 這邊長怎樣?
2. 前面方法 2 提到的
    > 把整個程式從 Memory dump 出來，並且將 Header 裡的進入點修改到真正的進入點
    
    怎麼做?

### 👀 The encrypted code at 004011XX
簡單一個截圖說明一切:
![](https://i.imgur.com/bQ0BLcC.png)
截自 Ghidra，還沒被還原時，長相長這樣
可以對比前章節已經還原後的 004011XX
OPcode 根本不一樣，表示說還原的步驟的確有對原程式動到手腳

### 😎 Dump the unpacked exe
這裡不得不說 x32dbg 真D好用
當 x32dbg 已跳到 OEP 時
從外掛程式(Plugin) -> Scylla
![](https://i.imgur.com/tz36rsU.png)
剛開起來長這樣

依序點 IAT Autosearch -> Get Imports -> Dump

假設輸出檔名為 Easy_UnpackMe_dump.exe
可以執行看看

![](https://i.imgur.com/GBewCdq.png)

此時還執行不起來

沒關係，再點 Fix Dump
選擇 Easy_UnpackMe_dump.exe

可以看到下面 Log 多了一條
![](https://i.imgur.com/96iOzRj.png)

再執行看看 Easy_UnpackMe_dump_SCY.exe
應該就是可以執行的了吧~~

再把它丟到 x32dbg
就可以發現一開始就直接進到 **004011XX**
你也可以自己用 PE Header 的欄位算算看是否是這個位置
這表示這支程式進入點是直接到 **004011XX**
這支程式已經是原本的程式，而非 Packed 程式
已經不需要經過**還原回原本程式**的 code 了

### Reference
[Dump the unpacked exe](https://goggleheadedhacker.com/blog/post/6)
[PE Header](https://upload.wikimedia.org/wikipedia/commons/1/1b/Portable_Executable_32_bit_Structure_in_SVG_fixed.svg)

## Easy_ELF
### 👀 Analyze
就在 Linux 中動態分析
發現一些簡單的 xor 囉

![](https://i.imgur.com/WFy24Ii.png)

斷點斷在 0x8048380

然後一直 follow follow follow
追到 \_\_libc\_start\_main+237 時
會跳到主要的 code

![](https://i.imgur.com/cSzgaNq.png)

輸入 si 走進去看看

![](https://i.imgur.com/eTxnCc3.png)

發現跳到 0x804851b
用 objdump 看一下這邊的 code

![](https://i.imgur.com/YvW75CH.png)

前面有三個連續 call
分別 call 了
- write@plt
    輸出訊息
- 0x8048434
- 0x8048451

### 👀 0x8048434
![](https://i.imgur.com/xMp38Zq.png)
只是一個 scanf
format 是 \"\%s\"
存到 0x804a020

### 👀 0x8048451
![](https://i.imgur.com/pTpBZIC.png)
這個小多
看看能不能變出一個圖形化的東西來看

這邊用 radare2
```
r2 Easy_ELF
```

輸入 s 跳到這個地址
```
s 0x8048451
```

跑一下分析，等等才能產生圖
```
aaa
```

最後來看圖
```
VV
```

![](https://i.imgur.com/vBiJTSJ.jpg)

到這個畫面，可以用方向鍵來移動

![](https://i.imgur.com/xH7tnTc.jpg)
目標是要進到右下角 mov eax, 1 的區塊 然後 return，表示成功驗證
到這邊之後，就很好解了


<!-- -->

<style>
/* fix mathjax rwd scroll
 * #Research-direction > simple model
 */
ul > li > .mathjax {
    overflow-x: scroll;
    overflow-y: hidden;
    overflow-wrap: break-word;
    display: inline-block;
}
#doc > ul:nth-child(38) > li:nth-child(4) > ul > li > .mathjax {
    width: 100%;
}

/* Dark mode */

/* <!-- todo: fix highlight.js blocks; some code blocks do not render correctly --> */

.navbar-default {
    background-color: #091a22;
}
.navbar-default .navbar-brand,
.ui-infobar {
    color: #ebebeb;
}

body {
    background-color: #23272a !important;
}

.ui-view-area {
    background: #23272a;
    color: #ddd;
}

.ui-toc-dropdown {
    background-color: #23272A;
    border: 1px solid rgba(255,255,255,.15);
    box-shadow: 0 6px 12px rgba(255,255,255,.175);
}

.ui-toc-dropdown .nav > li > a {
    color: #ccc;
}

.ui-toc-dropdown .nav > .active:focus > a,
.ui-toc-dropdown .nav > .active:hover > a,
.ui-toc-dropdown .nav > .active > a {
    color: #bbb;
}

.ui-toc .open .ui-toc-label {
    color: #777;
}

table * {
    background-color: #424242;
    color: #c0c0c0
}

button,
a {
    color: #64B5F6;
}

a:hover,
a:focus {
    color: #2196F3;
}

a.disable,
a.disable:hover {
    color: #EEEEEE;
}

/* Dark mode code block */
/* Imported from titangene/hackmd-dark-theme */

.markdown-body pre {
    background-color: #1e1e1e;
    border: 1px solid #555 !important;
    color: #dfdfdf;
    font-weight: 600;
}
.token.operator, .token.entity,
.token.url, .language-css .token.string,
.style .token.string {
    background: unset;
}

/* Dark mode alert boxes */

.alert-info {
    color: #f3fdff;
    background: #40788A;
    border-color: #2F7A95;
}

.alert-warning {
    color: #fffaf2;
    background: #936C36;
    border-color: #AE8443;
}

.alert-danger {
    color: #fff4f4;
    background: #834040;
    border-color: #8C2F2F
}

.alert-success {
    color: #F4FFF2;
    background-color: #436643;
    border-color: #358A28;
}

/* Stylized alert boxes */

.alert-danger>p::before {
    content: "❌ Dangerous\A";
}

.alert-warning>p::before {
    content: "⚠ Warning\A";
}

.alert-info>p::before {
    content: "ℹ  Information\A";
}

.alert-warning>p::before,
.alert-danger>p::before,
.alert-info>p::before {
    white-space: pre;
    font-weight: bold;
}

</style>

<style>
/*
 * Visual Studio 2015 dark style
 * Author: Nicolas LLOBERA <nllobera@gmail.com>
 */

.hljs {
  display: block;
  overflow-x: auto;
  padding: 0.5em;
  background: #1E1E1E;
  color: #DCDCDC;
}

.hljs-keyword,
.hljs-literal,
.hljs-symbol,
.hljs-name {
  color: #569CD6;
}
.hljs-link {
  color: #569CD6;
  text-decoration: underline;
}

.hljs-built_in,
.hljs-type {
  color: #4EC9B0;
}

.hljs-number,
.hljs-class {
  color: #B8D7A3;
}

.hljs-string,
.hljs-meta-string {
  color: #D69D85;
}

.hljs-regexp,
.hljs-template-tag {
  color: #9A5334;
}

.hljs-subst,
.hljs-function,
.hljs-title,
.hljs-params,
.hljs-formula {
  color: #DCDCDC;
}

.hljs-comment,
.hljs-quote {
  color: #57A64A;
  font-style: italic;
}

.hljs-doctag {
  color: #608B4E;
}

.hljs-meta,
.hljs-meta-keyword,
.hljs-tag {
  color: #9B9B9B;
}

.hljs-variable,
.hljs-template-variable {
  color: #BD63C5;
}

.hljs-attr,
.hljs-attribute,
.hljs-builtin-name {
  color: #9CDCFE;
}

.hljs-section {
  color: gold;
}

.hljs-emphasis {
  font-style: italic;
}

.hljs-strong {
  font-weight: bold;
}

/*.hljs-code {
  font-family:'Monospace';
}*/

.hljs-bullet,
.hljs-selector-tag,
.hljs-selector-id,
.hljs-selector-class,
.hljs-selector-attr,
.hljs-selector-pseudo {
  color: #D7BA7D;
}

.hljs-addition {
  background-color: #144212;
  display: inline-block;
  width: 100%;
}

.hljs-deletion {
  background-color: #600;
  display: inline-block;
  width: 100%;
}

</style>