added first article
This commit is contained in:
parent
26d46413f1
commit
1f3538e47d
2
Makefile
2
Makefile
@ -5,6 +5,6 @@ default: all
|
||||
|
||||
all: embed libdzonerzy libdzonerzy-gen
|
||||
|
||||
runlocal: libdzonerzy-runlocal
|
||||
runlocal: embed libdzonerzy-runlocal
|
||||
|
||||
clean: clean-tools clean-libdzonerzy
|
@ -21,7 +21,7 @@ SITE_DIST = dist/site
|
||||
AWK_UTIL = awk '/^\s*\[[0-9]+\]\s+([^\.].+)/ {print $$2}'
|
||||
AWK_UTIL_NOCRLF = awk '/^\s*\[[0-9]+\]\s+([^\.].+)/ {printf $$2" "}'
|
||||
|
||||
PANDOC_ARGS = --standalone --table-of-contents --section-divs --email-obfuscation=references --css=main.css --include-after-body=$(RAW_DIST)/footer.html
|
||||
PANDOC_ARGS = --standalone --table-of-contents --section-divs --email-obfuscation=references --css="/main.css" --include-after-body=$(RAW_DIST)/footer.html --include-after-body=$(RAW_DIST)/scripts.html
|
||||
|
||||
libdzonerzy:
|
||||
@echo "/* DO NOT EDIT THIS FILE - it is machine generated */" > $(SRC_DIR)/res.h
|
||||
@ -38,14 +38,17 @@ libdzonerzy-dump:
|
||||
|
||||
libdzonerzy-gen: libdzonerzy-dump
|
||||
@mkdir -p $(SITE_DIST)/assets/
|
||||
@mkdir -p $(SITE_DIST)/articles/
|
||||
@$(foreach page, $(wildcard $(RAW_DIST)/pages/*), $(PANDOC) $(PANDOC_ARGS) --from=markdown --to=html --output=$(shell echo $(SITE_DIST)/$(notdir $(page)) | sed 's/\.md/\.html/') $(page);)
|
||||
@$(foreach article, $(wildcard $(RAW_DIST)/articles/*), $(PANDOC) $(PANDOC_ARGS) --from=markdown --to=html --output=$(shell echo $(SITE_DIST)/articles/$(notdir $(article)) | sed 's/\.md/\.html/') $(article);)
|
||||
@cp $(RAW_DIST)/main.css $(SITE_DIST)/main.css
|
||||
@cp $(RAW_DIST)/main.js $(SITE_DIST)/main.js
|
||||
@cp $(RAW_DIST)/sitemap.xml $(SITE_DIST)/sitemap.xml
|
||||
@cp -r $(RAW_DIST)/embed/* $(SITE_DIST)/assets/
|
||||
@cp $(DIST)/libdzonerzy.so $(SITE_DIST)/libdzonerzy.so
|
||||
@chmod -R 755 $(SITE_DIST)/*
|
||||
|
||||
libdzonerzy-runlocal:
|
||||
libdzonerzy-runlocal: libdzonerzy libdzonerzy-gen
|
||||
@cd $(SITE_DIST) && python3 -m http.server 8080
|
||||
|
||||
clean-libdzonerzy:
|
||||
|
@ -23,10 +23,14 @@ Copyright:
|
||||
#define MAIN_CSS \
|
||||
CSS_COMMENT("main.css") \
|
||||
CSS_NEWLINE() \
|
||||
CSS_SELECTOR(":root") \
|
||||
CSS_PROPERTY("--main-link-color", "#215fc2") \
|
||||
CSS_END_SELECTOR() \
|
||||
CSS_SELECTOR("html,body") \
|
||||
CSS_PROPERTY("margin", "0") \
|
||||
CSS_PROPERTY("padding", "0") \
|
||||
CSS_PROPERTY("width", "100%") \
|
||||
CSS_PROPERTY("height", "100vh") \
|
||||
CSS_END_SELECTOR() \
|
||||
CSS_SELECTOR("body") \
|
||||
CSS_PROPERTY("font-family", "monospace") \
|
||||
@ -44,11 +48,9 @@ Copyright:
|
||||
CSS_PROPERTY("padding", "1em") \
|
||||
CSS_END_SELECTOR() \
|
||||
CSS_SELECTOR("footer") \
|
||||
CSS_PROPERTY("border", "1px solid #222") \
|
||||
CSS_PROPERTY("border-radius", "15px") \
|
||||
CSS_PROPERTY("border-top", "1px solid #222") \
|
||||
CSS_PROPERTY("background-color", "#ccc") \
|
||||
CSS_PROPERTY("color", "#000") \
|
||||
CSS_PROPERTY("margin", "1em") \
|
||||
CSS_PROPERTY("padding", "1em") \
|
||||
CSS_PROPERTY("flex-shrink", "0") \
|
||||
CSS_PROPERTY("display", "flex") \
|
||||
@ -161,14 +163,46 @@ Copyright:
|
||||
CSS_END_SELECTOR() \
|
||||
CSS_SELECTOR("pre::-webkit-scrollbar") \
|
||||
CSS_PROPERTY("display", "none") \
|
||||
CSS_END_SELECTOR() \
|
||||
CSS_SELECTOR("a") \
|
||||
CSS_PROPERTY("text-decoration", "none") \
|
||||
CSS_PROPERTY("color", "var(--main-link-color)") \
|
||||
CSS_END_SELECTOR() \
|
||||
CSS_SELECTOR("a:visted") \
|
||||
CSS_PROPERTY("color", "var(--main-link-color)") \
|
||||
CSS_END_SELECTOR() \
|
||||
CSS_SELECTOR(".modal") \
|
||||
CSS_PROPERTY("position", "fixed") \
|
||||
CSS_PROPERTY("top", "0") \
|
||||
CSS_PROPERTY("left", "0") \
|
||||
CSS_PROPERTY("width", "100%") \
|
||||
CSS_PROPERTY("height", "100%") \
|
||||
CSS_PROPERTY("background-color", "rgba(0,0,0,0.7)") \
|
||||
CSS_PROPERTY("z-index", "9999") \
|
||||
CSS_PROPERTY("cursor", "zoom-out") \
|
||||
CSS_END_SELECTOR() \
|
||||
CSS_SELECTOR(".modal img") \
|
||||
CSS_PROPERTY("min-height", "80vh") \
|
||||
CSS_PROPERTY("max-height", "80vh") \
|
||||
CSS_PROPERTY("width", "auto") \
|
||||
CSS_PROPERTY("max-width", "95vw") \
|
||||
CSS_PROPERTY("position", "absolute") \
|
||||
CSS_PROPERTY("top", "50%") \
|
||||
CSS_PROPERTY("left", "50%") \
|
||||
CSS_PROPERTY("transform", "translate(-50%, -50%)") \
|
||||
CSS_PROPERTY("margin", "0") \
|
||||
CSS_END_SELECTOR() \
|
||||
CSS_SELECTOR(".zoomable") \
|
||||
CSS_PROPERTY("max-width", "60vw") \
|
||||
CSS_PROPERTY("max-height", "45vh") \
|
||||
CSS_END_SELECTOR()
|
||||
|
||||
#define INDEX_MD \
|
||||
MD_META("DZONERZY's Blog", "DZONERZY") \
|
||||
MD_META_CUSTOM("Thursday 12 July 2023") \
|
||||
MD_META_CUSTOM("Wednesday, July 12, 2023") \
|
||||
MD_NEWLINE() \
|
||||
MD_SECTION1("About") \
|
||||
MD_IMAGE("Picture of DZONERZY", "assets/dzonerzy.jpg") \
|
||||
MD_IMAGE_ATTR("Picture of DZONERZY", "assets/dzonerzy.jpg", "class", "zoomable") \
|
||||
MD_TEXT("Hello world here is dzonerzy, also known as Daniele Linguaglossa,") \
|
||||
MD_TEXT("I'm an offensive security researcher and developer.") \
|
||||
MD_NEWLINE() \
|
||||
@ -196,6 +230,15 @@ Copyright:
|
||||
MD_TEXT(" -- CaptainHook is the next-gen hooking framework, it's a library that ") \
|
||||
MD_TEXT("allow to hook functions in a very easy way without knowing the function prototype.") \
|
||||
MD_NEWLINE() \
|
||||
MD_SECTION1("Articles") \
|
||||
MD_TEXT("Below you can find a list of my articles, I'm writing articles about ") \
|
||||
MD_TEXT("offensive security and programming, I'm also writing articles about ") \
|
||||
MD_TEXT("my projects.") \
|
||||
MD_NEWLINE() \
|
||||
MD_LIST(MD_BOLD(MD_LINK("CaptainHook next-gen hooking framework", \
|
||||
"/articles/captainhook-a-next-gen-hooking-framework.html"))) \
|
||||
MD_TEXT(" -- A different approach to prototype-less hooking.") \
|
||||
MD_NEWLINE() \
|
||||
MD_SECTION1("FAQ") \
|
||||
MD_TEXT("Here is a list of frequently asked questions, if you have any other questions ") \
|
||||
MD_TEXT("feel free to contact me at ") \
|
||||
@ -222,13 +265,11 @@ Copyright:
|
||||
MD_LIST(MD_BOLD("Q: ") MD_TEXT("Is Sysdig hiring?")) \
|
||||
MD_NEWLINE() \
|
||||
MD_TEXT("Yes, we are always looking for new talents, if you are interested in working ") \
|
||||
MD_TEXT("with me, feel free to send your resume at ... try to find it :D , ") \
|
||||
MD_TEXT("hint (") \
|
||||
MD_BOLD("libdzonerzy.so") \
|
||||
MD_TEXT(").") \
|
||||
MD_TEXT("with me, feel free to send your resume at ... try to find it, after all it's still ") \
|
||||
MD_TEXT("\"inside\" this blog.") \
|
||||
MD_NEWLINE()
|
||||
|
||||
#define FOOTER_MD \
|
||||
#define FOOTER_HTML \
|
||||
MD_RAWTAG("footer", "" \
|
||||
"<span>" \
|
||||
"Powered by <a href=\"/libdzonerzy.so\">libdzonerzy.so</a>" \
|
||||
@ -237,12 +278,103 @@ Copyright:
|
||||
"<span>made with <div class='hearth'>❤</div> by <b class='author'>dzonerzy</b></span>") \
|
||||
MD_NEWLINE()
|
||||
|
||||
#define SCRIPTS_HTML \
|
||||
HTML_TAG_OPEN_CONTENT("script", "src=\"/main.js\"", "") \
|
||||
HTML_TAG_OPEN("script", "type=\"text/javascript\"") \
|
||||
HTML_RAWTEXT("var _gaq = _gaq || [];") \
|
||||
HTML_NEWLINE() \
|
||||
HTML_RAWTEXT("_gaq.push(['_setAccount', 'UA-XXXXX-X']);") \
|
||||
HTML_NEWLINE() \
|
||||
HTML_RAWTEXT("_gaq.push(['_trackPageview']);") \
|
||||
HTML_NEWLINE() \
|
||||
HTML_RAWTEXT("(function() {") \
|
||||
HTML_NEWLINE() \
|
||||
HTML_RAWTEXT("var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;") \
|
||||
HTML_NEWLINE() \
|
||||
HTML_RAWTEXT("ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';") \
|
||||
HTML_NEWLINE() \
|
||||
HTML_RAWTEXT("var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);") \
|
||||
HTML_NEWLINE() \
|
||||
HTML_RAWTEXT("})();") \
|
||||
HTML_NEWLINE() \
|
||||
HTML_TAG_CLOSE("script") \
|
||||
HTML_NEWLINE()
|
||||
|
||||
// wait for page ready and then execute the code don't use jQuery
|
||||
// because it's a static website and I don't want to use external
|
||||
// libraries
|
||||
// use a div with class modal to show the image
|
||||
// the image must maintain the aspect ratio
|
||||
// the image must be centered
|
||||
|
||||
#define MAIN_JS \
|
||||
HTML_RAWTEXT("function zoomImages() {") \
|
||||
HTML_NEWLINE() \
|
||||
HTML_RAWTEXT("var imgs = document.getElementsByClassName('zoomable');") \
|
||||
HTML_NEWLINE() \
|
||||
HTML_RAWTEXT("for (var i = 0; i < imgs.length; i++) {") \
|
||||
HTML_NEWLINE() \
|
||||
HTML_RAWTEXT("imgs[i].style.cursor = 'zoom-in';") \
|
||||
HTML_NEWLINE() \
|
||||
HTML_RAWTEXT("imgs[i].addEventListener('click', function() {") \
|
||||
HTML_NEWLINE() \
|
||||
HTML_RAWTEXT("var modal = document.createElement('div');") \
|
||||
HTML_NEWLINE() \
|
||||
HTML_RAWTEXT("modal.className = 'modal';") \
|
||||
HTML_NEWLINE() \
|
||||
HTML_RAWTEXT("modal.addEventListener('click', function() {") \
|
||||
HTML_NEWLINE() \
|
||||
HTML_RAWTEXT("modal.parentNode.removeChild(modal);") \
|
||||
HTML_NEWLINE() \
|
||||
HTML_RAWTEXT("});") \
|
||||
HTML_NEWLINE() \
|
||||
HTML_RAWTEXT("var img = document.createElement('img');") \
|
||||
HTML_NEWLINE() \
|
||||
HTML_RAWTEXT("img.src = this.src;") \
|
||||
HTML_NEWLINE() \
|
||||
HTML_RAWTEXT("modal.appendChild(img);") \
|
||||
HTML_NEWLINE() \
|
||||
HTML_RAWTEXT("document.body.appendChild(modal);") \
|
||||
HTML_NEWLINE() \
|
||||
HTML_RAWTEXT("});") \
|
||||
HTML_NEWLINE() \
|
||||
HTML_RAWTEXT("}") \
|
||||
HTML_NEWLINE() \
|
||||
HTML_RAWTEXT("}") \
|
||||
HTML_NEWLINE() \
|
||||
HTML_RAWTEXT("document.addEventListener('DOMContentLoaded', function() {") \
|
||||
HTML_NEWLINE() \
|
||||
HTML_RAWTEXT("zoomImages();") \
|
||||
HTML_NEWLINE() \
|
||||
HTML_RAWTEXT("});") \
|
||||
HTML_NEWLINE()
|
||||
|
||||
#define SITEMAP_XML \
|
||||
XML_URLSET() \
|
||||
XML_URL("https://libdzonerzy.so/index.html") \
|
||||
XML_URL("https://libdzonerzy.so/sitemap.xml") \
|
||||
XML_END_URLSET()
|
||||
|
||||
#define CAPTAINHOOK_MD \
|
||||
MD_META("CaptainHook - A different approach to prototype-less hooking", "DZONERZY") \
|
||||
MD_META_CUSTOM("Thursday, July 13, 2023") \
|
||||
MD_SECTION1("CaptainHook -- A different approach to prototype-less hooking") \
|
||||
MD_TEXT("CaptainHook is a new hooking framework that allows you to hook ") \
|
||||
MD_TEXT("functions without the need of a prototype. ") \
|
||||
MD_NEWLINE() \
|
||||
MD_TEXT("It uses a different approach to hooking, instead of modifying the ") \
|
||||
MD_TEXT("function prologue, it before perform the emulation of the function ") \
|
||||
MD_TEXT("in three different points: ") \
|
||||
MD_NEWLINE() \
|
||||
MD_TEXT("1. Before the function is called ") \
|
||||
MD_NEWLINE() \
|
||||
MD_TEXT("2. After the function is called ") \
|
||||
MD_NEWLINE() \
|
||||
MD_TEXT("3. Before the function returns ") \
|
||||
MD_NEWLINE() \
|
||||
MD_LINK("< Back", "/") \
|
||||
MD_NEWLINE()
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
fprintf(stdout, "https://libdzonerzy.so\n");
|
||||
@ -255,6 +387,12 @@ static const char maincss[] = MAIN_CSS;
|
||||
SECTION("pages/index.md")
|
||||
static const char indexmd[] = INDEX_MD;
|
||||
SECTION("footer.html")
|
||||
static const char footermd[] = FOOTER_MD;
|
||||
static const char footerhtml[] = FOOTER_HTML;
|
||||
SECTION("scripts.html")
|
||||
static const char scriptshtml[] = SCRIPTS_HTML;
|
||||
SECTION("main.js")
|
||||
static const char mainjs[] = MAIN_JS;
|
||||
SECTION("sitemap.xml")
|
||||
static const char sitemapxml[] = SITEMAP_XML;
|
||||
ARTICLE("captainhook-a-next-gen-hooking-framework")
|
||||
static const char captainhook[] = CAPTAINHOOK_MD;
|
@ -77,6 +77,8 @@ Copyright:
|
||||
#define MD_LINK(x, y) "[" x "](" y ")"
|
||||
// image macros
|
||||
#define MD_IMAGE(x, y) "![" x "](" y ")\n\n"
|
||||
// image macros with attributes
|
||||
#define MD_IMAGE_ATTR(x, y, a, v) "![" x "](" y "){" a "=\"" v "\"}\n\n"
|
||||
// raw html tag macros
|
||||
#define MD_RAWTAG(t, c) "<" t ">" c "</" t ">"
|
||||
// new line macros
|
||||
@ -103,180 +105,16 @@ Copyright:
|
||||
// end urlset macros
|
||||
#define XML_END_URLSET() "</urlset>\n"
|
||||
|
||||
/*#define STACK_SIZE 10 * 1024
|
||||
|
||||
enum Flags
|
||||
{
|
||||
EQ = 1 << 0,
|
||||
GT = 1 << 1,
|
||||
LT = 1 << 2,
|
||||
};
|
||||
|
||||
typedef struct machine
|
||||
{
|
||||
uint32_t R;
|
||||
uint32_t SP;
|
||||
uint32_t FL;
|
||||
uint8_t *stack;
|
||||
} machine_t, *pmachine_t;
|
||||
|
||||
#define C_START \
|
||||
int fd[2]; \
|
||||
char *b = "a"; \
|
||||
int fd2; \
|
||||
int *m; \
|
||||
int a; \
|
||||
char *c; \
|
||||
int *p;
|
||||
|
||||
#define sys_write(x, y, z) \
|
||||
__asm__ __volatile__("syscall" \
|
||||
: \
|
||||
: "a"(1), "D"(x), "S"(y), "d"(z))
|
||||
|
||||
#define sys_pipe(x) \
|
||||
__asm__ __volatile__("syscall" \
|
||||
: \
|
||||
: "a"(22), "D"(x))
|
||||
|
||||
#define sys_close(x) \
|
||||
__asm__ __volatile__("syscall" \
|
||||
: \
|
||||
: "a"(3), "D"(x))
|
||||
|
||||
#define sys_fork() \
|
||||
({ \
|
||||
int ret; \
|
||||
__asm__ __volatile__("syscall" \
|
||||
: "=a"(ret) \
|
||||
: "a"(57)); \
|
||||
ret; \
|
||||
})
|
||||
|
||||
#define sys_kill(x, y) \
|
||||
__asm__ __volatile__("movl %0, %%edi;" \
|
||||
"movl %1, %%esi;" \
|
||||
"mov $62, %%rax;" \
|
||||
"syscall;" \
|
||||
: \
|
||||
: "r"(x), "r"(y) \
|
||||
: "edi", "esi", "rax")
|
||||
|
||||
// getpid and save to pid variable
|
||||
#define sys_getpid() \
|
||||
({ \
|
||||
int ret; \
|
||||
__asm__ __volatile__("syscall" \
|
||||
: "=a"(ret) \
|
||||
: "a"(39)); \
|
||||
ret; \
|
||||
})
|
||||
|
||||
#define sys_open(a1, a2, a3) \
|
||||
({ \
|
||||
unsigned long ret; \
|
||||
__asm__ __volatile__("syscall" \
|
||||
: "=a"(ret) \
|
||||
: "a"(2), "D"(a1), "S"(a2), "d"(a3) \
|
||||
: "rcx", "r11", "memory"); \
|
||||
ret; \
|
||||
})
|
||||
|
||||
#define sys_mmap(a1, a2, a3, a4, a5, a6) \
|
||||
({ \
|
||||
unsigned long ret; \
|
||||
register long r10 __asm__("r10") = a4; \
|
||||
register long r8 __asm__("r8") = a5; \
|
||||
register long r9 __asm__("r9") = a6; \
|
||||
__asm__ __volatile__("syscall" \
|
||||
: "=a"(ret) \
|
||||
: "a"(9), "D"(a1), "S"(a2), \
|
||||
"d"(a3), "r"(r10), "r"(r8), "r"(r9) \
|
||||
: "rcx", "r11", "memory"); \
|
||||
ret; \
|
||||
})
|
||||
|
||||
#define sys_munmap(a1, a2) \
|
||||
asm volatile("syscall" \
|
||||
: \
|
||||
: "a"(11), "D"(a1), "S"(a2) \
|
||||
: "rcx", "r11", "memory");
|
||||
|
||||
#define C_SIGPIPE(c) \
|
||||
sys_pipe(fd); \
|
||||
sys_close(fd[0]); \
|
||||
sys_write(fd[1], b, 1); \
|
||||
__asm__(".byte " #c);
|
||||
|
||||
#define C_SIGTRAP(c) \
|
||||
__asm__("int3"); \
|
||||
__asm__(".byte " #c);
|
||||
|
||||
#define C_SIGILL(j1, j2, x, k) \
|
||||
__asm__("ud2"); \
|
||||
__asm__(".byte " #x); \
|
||||
if (k) \
|
||||
{ \
|
||||
__asm__ __volatile__ goto("jmp %l0" \
|
||||
: \
|
||||
: \
|
||||
: \
|
||||
: j1); \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
__asm__ __volatile__ goto("jmp %l0" \
|
||||
: \
|
||||
: \
|
||||
: \
|
||||
: j2); \
|
||||
}
|
||||
|
||||
#define C_SIGFPE(c) \
|
||||
__asm__("mov $1, %rax"); \
|
||||
__asm__("mov $0, %rbx"); \
|
||||
__asm__("div %rbx"); \
|
||||
__asm__(".byte " #c);
|
||||
|
||||
#define C_SIGSEGV(c) \
|
||||
*(int *)0xffffffffffff = 1; \
|
||||
__asm__(".byte " #c);
|
||||
|
||||
#define C_SIGTERM(c) \
|
||||
sys_kill(process_pid, SIGTERM); \
|
||||
__asm__(".byte " #c);
|
||||
|
||||
#define C_SIGXCPU(c) \
|
||||
sys_kill(process_pid, SIGXCPU); \
|
||||
__asm__(".byte " #c);
|
||||
|
||||
#define C_SIGSYS(c) \
|
||||
sys_kill(process_pid, SIGSYS); \
|
||||
__asm__(".byte " #c);
|
||||
|
||||
#define C_SIGBUS(v) \
|
||||
__asm__("pushf\norl $0x40000,(%rsp)\npopf"); \
|
||||
a = 0xffffff; \
|
||||
c = (char *)&a; \
|
||||
c++; \
|
||||
p = (int *)c; \
|
||||
*p = 10; \
|
||||
__asm__(".byte " #v); \
|
||||
__asm__("pushf\nxorl $0x40000,(%rsp)\npopf");
|
||||
|
||||
#define C_SIGXFSZ(c) \
|
||||
sys_kill(process_pid, SIGXFSZ); \
|
||||
__asm__(".byte " #c);
|
||||
|
||||
#define C_END \
|
||||
sys_close(fd[0]); \
|
||||
sys_close(fd[1]);
|
||||
|
||||
#define OP_ADD 0xd1
|
||||
#define OP_SUB 0x71
|
||||
#define OP_MUL 0xf7
|
||||
#define OP_DIV 0x7f
|
||||
#define OP_MOD 0x3c
|
||||
#define OP_XOR 0x5a
|
||||
#define OP_AND 0x2d
|
||||
#define OP_OR 0x6e*/
|
||||
// HTML macros
|
||||
// html tag macros
|
||||
#define HTML_TAG(t, c) "<" t ">\n" c "</" t ">\n"
|
||||
// html tag macros open
|
||||
#define HTML_TAG_OPEN(t, a) "<" t " " a ">\n"
|
||||
// html tag macros with attributes and content
|
||||
#define HTML_TAG_OPEN_CONTENT(t, a, c) "<" t " " a ">\n" c "</" t ">\n"
|
||||
// html tag macros close
|
||||
#define HTML_TAG_CLOSE(t) "</" t ">"
|
||||
// html raw text macros
|
||||
#define HTML_RAWTEXT(x) x
|
||||
// html new line macros
|
||||
#define HTML_NEWLINE() "\n"
|
||||
|
Loading…
Reference in New Issue
Block a user