“你好,世界!” (强盗的线程)


11

这是强盗的线索。警察的线在这里

您面临的挑战是从警察的线程中获取完整的意见,并找出程序将打印什么和输入Hello, World!换行符。大写字母,空格和标点符号必须准确。

破解他们的代码后,请对警察的意见发表评论。

Answers:


12

重击由西西弗斯

原始代码:

[[ ! "${1////x}" =~ [[:alnum:]] ]]&&[[ $# = 1 ]]&&bash -c "$1"

输入:

__=; (( __++, __-- ));
(( ___        = __,        ___++));
(( ____       = ___,       ____++));
(( _____      = ____,      _____++));
(( ______     = _____,     ______++));
(( _______    = ______,    _______++));
(( ________   = _______,   ________++));
(( _________  = ________,  _________++));

${!__##-} <<<\$\'\\$___$______$_______\\$___$______$_____\\$___$_______$__\\$___$_______$_________\'\ \$\'\\$___$___$__\\$___$______$_______\\$___$_______$______\\$___$_______$______\\$___$_______$_________,\ \\$___$____$_________\\$___$_______$_________\\$___$________$____\\$___$_______$______\\$___$______$______\\$__$______$___\'

说明:

这编码为“回声你好,世界!” 作为八进制转义序列(\ xxx)。

除了您也不能使用数字外,因此第一部分为数字0-7建立变量。您可以使用它们来构建具有八进制序列的字符串,这些字符串的计算结果将为您提供实际的命令。

但是eval也是字母数字。因此,它将此字符串作为输入传递给的另一个实例bash$0包含用于调用Bash的命令的名称,如果您正常运行(通过TIO或通过将其粘贴到终端中),则该名称通常只是bash(或-bash用于登录shell)。(顺便说一句,这意味着如果您尝试通过将其粘贴到脚本中来运行它,则由于它尝试分叉多次,事情将变得非常错误。)

但是无论如何,你不能$0直接说。相反,$__包含名称$0(“0”),并且可以使用间接扩展访问它(${!__}指中的内容$0)。

最后,它为您提供了所需的所有部件。


欢迎来到编程难题和代码高尔夫球!我对警察的回答发表了评论。感兴趣的TIO链接:tio.run / ## jc /…
丹尼斯,

真好!我的解决方案看起来有所不同,但是使用了相同的想法-构造一个八进制字符串,并使用美元单引号语法,并使用了间接寻址。做得好=)
西西弗斯(Sisyphus




3

果冻:EriktheOutgolfer

〡㋄ⶐ✐сᑀ⟙ⶐⶐ〡ސЀᶑ〡㋄ⶐ✐сᑀ⟙ⶐⶐ〡ސЀᶑ〡㋄ⶐ✐сᑀ⟙ⶐⶐ〡ސЀᶑ〡㋄ⶐ✐сᑀ⟙ⶐⶐ〡ސЀᶑ〡㋄ⶐ✐сᑀ⟙ⶐⶐ〡ސЀᶑ〡㋄ⶐ✐сᑀ⟙ⶐⶐ〡ސЀᶑ〡㋄ⶐ✐сᑀ⟙ⶐⶐ〡ސЀᶑ〡㋄ⶐ✐сᑀ⟙ⶐⶐ〡ސЀᶑ〡㋄ⶐ✐сᑀ⟙ⶐⶐ〡ސЀᶑ〡㋄ⶐ✐сᑀ⟙ⶐⶐ〡ސЀᶑ〡㋄ⶐ✐сᑀ⟙ⶐⶐ〡ސЀᶑ〡㋄ⶐ✐сᑀ⟙ⶐⶐ〡ސЀᶑ〡㋄ⶐ✐сᑀ⟙ⶐⶐ〡ސЀᶑ

果冻,11字节

sLƽ$Xṙ5O½Ọ

在线尝试!

说明

原始代码可以这样解释:

sLƽ$Xṙ5O½Ọ  Main link; argument is z
s            Split z into n slices, where n is:
    $
  ƽ         The integer square root of
 L                                      the length of z
     X       Random of a list. Returns a random row of the input put into a square
      ṙ5     Rotate the list left 5 times
        O    Get codepoints
         ½   Floating-point square root
          Ọ  From codepoints

因此,只需选择“你好,世界!” 并获得代码点,将它们平方,然后投射回代码点,向右旋转5次,然后对结果进行平方和展平。


3

Stewie Griffin的八度音阶

不知道这是否是正确的解决方案(在TIO上它会打印\00字符),但是在我的octave-clishell中,它看起来像这样:

八度音壳

同样在最初的挑战中,它说什么也不打印(或null字符),所以如果没有什么相同,\00那么应该没问题。

[72, 101, 108, 108, 111, 44, 32, 87, 111, 114, 108, 100, 33, 0]

在线尝试!



但这不是挑战的样子,如果那样的话,这会让我容易得多(用代替最后0一个10)。
ბიმო

@BruceForte这挑战问什么:“你的挑战是写一个程序或功能,具有一定的输入,打印出精确的字符串Hello, World!和换行。” 是挑战的确切报价。确实,这使答案变得微不足道。
hvd

@hvd是的,但是如果您查看OP的图像,他的解决方案就不会了,这就是主要的困惑所在。
ბიმო

1
@HyperNeutrino FWIW 是我认为解决方案的预期样式。
乔纳森·艾伦,


3

JavaScript(ES6),作者:Ephellon Dantzler

{length:1, charCodeAt:()=>(e='Hello, World!', String.fromCharCode=()=>'')}

在线尝试!

那很容易。

我注意到任何字符串输入都将无法输出,Hello, World!因为里面的整个东西String.fromCharCode只会返回4的倍数,并且!char码为33。所以很显然,我们只需要破解整个程序即可。如果不尝试阻止内置JavaScript,那么对它们进行黑客攻击就显得微不足道了(即使这样做,通常也有很多解决方法...)。


3

JavaScript(ES6),Voile

简单代理,仅在第3次调用时返回所需字符。

var i = 0;
var string = "Hello, World!";
var proxy = new Proxy([], {
  get: function(target, property) {
    if (!(++i%3)) {
      return string[property];
    }
    return [1];
  }
});

在线尝试!


2
是的,这是预期的解决方案:)代理需要更多的爱。
2017年

3

Ruby,由Histocrat

魔术输入是: 1767707618171221 30191World!

在线尝试。

说明:

  • 该数字1767707618171221为质数,用36为底数写成"hello"。大写时,产生"Hello",使用$><<
  • 该行在输入中$><<", #$'"if/30191/查找数字30191,然后将由逗号,空格和输入后的内容组成的字符串写入stdout 30191(使用$POSTMATCH,这是其简短的变体,在此引用$')。

3

Lua 5.1由Tehtmi

将其作为第一个参数传递:

C=("").char;_G[C(112,114,105,110,116)](C(72,101,108,108,111,44,32,87,111,114,108,100,33))

假设原始代码在file中tehtmi.lua,运行(在bash或类似的shell中):

lua tehtmi.lua 'C=("").char;_G[C(112,114,105,110,116)](C(72,101,108,108,111,44,32,87,111,114,108,100,33))'

它也可以在TIO使用的Lua 5.3上运行,所以为什么不在线尝试一下呢??我尚未在使用“ PUC-Rio的Lua 5.1”内核的实现上进行过测试(因为我无法真正找到任何信息),但是我的解决方案可能也可以在其中使用。

怎么样?

它以代码形式运行第一个参数,但前提是它包含少于5个小写字符。

诀窍是奔跑print("Hello, World!")。可以运行的另一种方法是使用_G["print"]("Hello, World!"),它仅使用字符串。

但是由于小写计数限制,我们不能直接使用字符串,但是,您可以运行("").char获取函数string.char,该函数可以将一系列字节转换为字符串。我将其分配给一个大写变量(因此我们没有达到极限),因此我们可以使用它来构造printHello, World!可以像上面一样使用的字符串。


啊,做得好!我正在考虑使用next而不是char因为迭代顺序的随机化而在Lua 5.3上不起作用。
tehtmi '17

3

Voile的JavaScript(ES6)

输入必须是包含以下内容的字符串:

e(
`\
_\
=\
>\
"\
H\
e\
l\
l\
o\
,\
 \
W\
o\
r\
l\
d\
!\
"\
+\
\`
\`
`)

使用以下方法尝试:

const e=eval,p=''.split,c=''.slice,v=[].every,f=s=>(t=c.call(s),typeof s=='string'&&t.length<81&&v.call(p.call(t,`\n`),l=>l.length<3)&&e(t)(t))

input='e(\n`\\\n_\\\n=\\\n>\\\n\"\\\nH\\\ne\\\nl\\\nl\\\no\\\n,\\\n \\\nW\\\no\\\nr\\\nl\\\nd\\\n!\\\n\"\\\n+\\\n\\`\n\\`\n`)'
console.log(f(input))

如果您不关心输出的尾随换行符要求,则可以用以下内容代替最后6行:

!"
`)

我是怎么做到的

输入的限制是它是一个字符串,每行的长度不超过两个字节,总长度不超过80个字节。我正确理解后的第一次尝试是:

_
=>
`\
H\
e\
l\
l\
o\
,\
 \
W\
o\
r\
l\
d\
!
`

注意:\s将忽略输入字符串中的换行符。这对答案至关重要,而且我无法相信我偶然发现了它。(我以前很熟悉但是却忘记了它)

但这是行不通的,因为=>必须与参数位于同一行。值得庆幸的是,我的想法是将类似的内容包装在字符串中,并在输入中添加一个eval以将其减少到一行,从而得出最终答案。输入中的eval发生后,将生成以下内容作为字符串(然后将其评估为函数,然后运行):

_=>"Hello, World!"+`
`

这确实很难破解,但最终我成功了。

另外,有史以来第一次破解!


3

立体地由MD XF

我想这总是很危险的,但是我认为我有一个裂缝,在我正确的解释是因为解释器中有一个错误(我刚刚编译)。

我的输入

0 1 0 1 0 1 0 1 1 0 1 0 0

输出是 Hello, World!\n\n\n\n\n\n\n\n\n\n.....带有无休止的换行符。

但是我注意到了代码的最后一部分:

:1/1+1$(@6)7

0x0A以一种令人恐惧的方式将记事本设置为(换行符),读取输入到面7(输入面),然后重复打印6面(记事本面),直到7面为零。如果将面7设置为零,则只能获得一个换行符。但是,我得到了无限的换行符,而我的第13个输入为0,可以通过在循环中插入“来自7面的打印编号”来验证7面始终为零:

:1/1+1$(@6%7)7

然后打印无休止 \n0对。

我正在看立方github页面上的规范,这种行为看起来很像个bug。将原始程序的最后一个字符从a 7更改为0预期的行为。TIO解释器表现出相同的错误行为。


现在应该修复,一旦丹尼斯(Dennis)立体地拉动,它将在TIO上修复。
MD XF


2

C#(.NET Core)GrzegorzPuławski

我发现的解决方案大量使用了无法打印的字符,因此尝试将其粘贴到此处效果不佳。输入的字节值是:

109, 89, 4, 121, 3, 11, 8, 29, 37, 38, 27, 25, 72, 4, 4, 4, 3, 3, 3, 4, 4, 37, 3, 27, 4, 3

或者字符串版本在TIO链接的输入字段中可用。

在线尝试!

原始程序将在输入中使用不同的字符,然后反转输入并将两个列表的元素相乘。因此,我创建了一个长26个字符的字符串,其中前13个字符是不同的,后13个字符也都出现在前13个字符中,每对索引[i, 26-i]个字符中乘以 i个字符的字节值Hello, World!


做得好!您设法省略了Take(a.First()-33)陷阱。这也使我意识到我忘记了在反向上的区别,但是哦,我仍然认为这是一个不错的挑战。它还具有%255,因此您可以使用可打印的ASCII更大的数字。
GrzegorzPuławski17年

2

LYLyricLy

n[>n]<[8+o<]

2 25 92 100 106 103 79 24 36 103 100 100 93 64

在这里尝试(尽管该页面不会显示换行符)。

n接受输入,尝试在空格上分割并转换为整数,然后将它们放入堆栈。o打印序数点,然后按照您的8+想法去做。因此,输入必须比按逆序除以空格的代码点小8。


这不会打印尾随的换行符,对吗?
LyricLy

哎呀,很容易纠正!
乔纳森·艾伦

...是吗?我本来以为2会工作-只是herokuapp页面无法呈现它吗?
乔纳森·艾伦

1
是的,添加2个作品。该页面只是不呈现尾随换行符。
LyricLy

2

C(gcc),作者费利克斯·帕尔明(Felix Palmen)

原始代码:

#define O(c)(((char**)v)+c)
#define W(c)*(O(c)-**O(2)+x)
main(x,v){puts(W(42));}

参数:

"Hello, World!" ","

在线尝试!

说明:

W(c)正在从参数列表计算字符串的地址以打印出来。它以cth参数(O(c))的地址开头,在本例中为第42个参数,然后减去第二个参数(**O(2))的第一个字符作为整数偏移量,然后加x,即参数的数量。

W(c)使用第二个参数,因此您知道至少需要3个(0、1、2)。然后是“你好,世界!” 可以在第一个参数中输入,然后要解决该参数,您需要一个字符,其ASCII值适合方程式“ 42-x + 3 = 1”。碰巧是“,”。


很棒的解释,我在PC上后就会立即编辑帖子:)
Felix Palmen

2

JavaScript:ThePirateBay

我覆盖了解析对象的valueOf()toString()方法,因此强制失败并带有TypeError

{"valueOf": 7, "toString": 7}

12
嗯,我似乎听不懂。请详细说明一下吗?特别是dalksdjalkdjaS djalksdjalksdja部分,这使我有些困惑。
暴民埃里克(Erik the Outgolfer)

@EriktheOutgolfer我编辑了垃圾邮件部分,但我不知道为什么它在那里。
NoOneIsHere

@EriktheOutgolfer哦,哈哈。那是为了阻止我的答案从自动转换为评论。
马蒂森(Maltysen)

1
@Maltysen好吧,那里有一个编辑按钮,下次可能会
用到

2

6502组装件(C64)-费利克斯·帕尔默(Felix Palmen)

正确的答案是,52768,23

略有涉及。

00 c0                          ;load address
20 fd ae      jsr $aefd        ; checks for comma
20 eb b7      jsr $b7eb        ; reads arguments

该代码首先检查逗号(语法是否必要),然后读取两个参数,第一个参数是WORD,将little-endian存储在存储器位置0014和0015中,后者存储在X寄存器中。

8a              TXA            ;Store second argument into A (default register)
0a              ASL            ; bitshifts the second argument left (doubles it)
45 14           EOR $14        ; XOR that with the low byte of first argument
8d 21 c0        STA $c021      ; Drop that later in the program

使用我们的输入重写程序,这非常聪明。最终,它在程序结尾重写输出循环的计数器。

45 15           EOR $15        ; XOR that with the high byte of the first argument
85 15           STA $15        ; Put the result in $15
49 e5           EOR #$e5       ; XOR that with the number $e5
85 14           STA $14        ; Put that in $14

这是曲折的部分:

8e 18 d0        STX $d018      ; stores the original second argument in d018

在C64上,d018是非常重要的字节。它存储涉及屏幕输出的事物的参考点。有关更多信息,请参见此处。如果此值输入错误,则会使您的C64崩溃。为了打印必需的大小写混合字母,这需要为$ 17。

现在我们开始输出循环:

a0 00               ldy #$00       ; zeroes out the Y register
b1 14               lda ($14),y    ; puts the memory referenced by the byte
                                   ;   starting at $14 (remember that byte?)
                                   ;   into the default register
20 d2 ff            jsr $ffd2      ; calls the kernal routine to print the char stored in A
c8                  iny            ; increment Y
c0 0e               cpy #$0e       ; test for equality with the constant $0e

这个常数就是以前写的。它清楚地确定了循环运行的时间。它恰好是正确的值,但是我们需要再次将0e粘贴在那里。

d0 f6                   bne *-8        ; jump back 8 bytes if y and that constant weren't equal
60                      rts            ; ends the program

剩下的只是我们需要打印的信息,从内存地址c025开始。

因此,它只是遵循那里的数学原理。


完全正确,恭喜。可能要花一些时间才能正确编辑我的信息,我现在处于移动状态。
菲利克斯·帕尔曼

d018非常聪明,我喜欢您暗中发布的提示。
A Gold Man

d018是打算打开的门...提示是偶然的,我的意思是$FF在那里,但随后决定离开它。
菲利克斯·帕尔门

2

6502机器代码(C64) -Felix Palmen

正确答案是

8位足够

代码相当复杂,涉及很多自我修改。因此,您可以使用它进行自我破解,而不是对其进行完全逆向工程。

这是一些反汇编的代码,有助于理解发生的情况。语法适用于KickAssembler。

*=$c000       // LOAD ADDRESS
jsr $aefd     //checks for a comma
jsr $ad9e     /*Reads in an argument. Stores length of it into
                $61, with the address of the stored arg in $62-3*/
jsr $b6a3     /*Evaluates the string, leaving the pointer on $22-3
                and the length on A*/ //I think

ldy #$00
loop: lda thedata,y   
cpy #$01
beq shuffle
cpy #$07
beq shuffle
cpy #$0b
beq shuffle
tricks: jsr output
iny
bne loop
output: eor ($22),y      //XOR's A with the y-eth letter of our input
jmp $ffd2               //good old CHROUT, returns to tricks above
thedata: .byte $f0,$48,$fa,$a2, $1c,$6d,$72,$30
.byte $06,$a9,$03,$48,$7c,$a3
shuffle: sta $c048      //drops A in mystery+4, over the constant
lda $c026,y
sta $c045               //overwrites the low byte of mystery
lda $c027,y
sta $c046               //overwrites the high byte of mystery
ldx #$00
mystery: lda $aefd,x              
eor #$23
jsr output
iny
inx
cpx #$03
bne mystery
cpy #$0e
bne loop
eor #$1a
sta $d018                
rts

像这样标记它足以让我看到代码对一系列隐藏的常量进行XOR,以便打印出所需的内容。由于XOR是可逆的,因此,如果您输入所需的输出,它将告诉您密钥是什么。

所以我换了最后一行

/*from sta $d018 
to*/ jsr $ffd2

因此它将打印最后需要的输入,而不是由于输入错误而崩溃。

就是这样!

如果有兴趣,我将进一步破解代码。


哇,这实际上是一个巨大的捷径,我可能应该在处理的早期就因输入错误而导致崩溃。使用的调试器,还有另一种可能的捷径。但是,无论如何,这是正确的解决方案。vice
菲利克斯·帕尔姆

我不知道恶习有调试器。这就是我学习语言以破解答案所获得的。
一位金级男子

编辑了我的帖子,并提供了一些说明。干得好,只修改程序当然不会崩溃是一种很明显的方法,我没有想到这一点。
菲利克斯·帕尔门

Nitpick:“ drops A in mystery+1, over the constant” <-实际上是mystery+4您的标签。代价是字节:)和FWIW,即使在严重的 6502代码中,只要代码从RAM运行,自我修改也是很常见的。
菲利克斯·帕尔梅

1

爆炸母鸡

@_?&4_-j>5&f^~c>&6\|4>7

Rh / qi?,Wcr + du

在线尝试!

  • 试图弄清楚所有“探索者”实际上在做什么,真是太伤人了头,所以我只是对它进行了反向工程(字面:p-从最右边的字符开始,我沿着[可打印的字符范围]依次偏移每个字符) 。

干得好:)我将在几个小时后回到电脑上添加一个解释
Stephen

1

C(tcc)由约书亚

int puts(const char *s)
{
    printf("Hello, World!%s", s);
}

在线尝试!


真是 我有这个确切的裂缝,但无法在TIO上运行。+1
MD XF

不好意思。一经发现,现在已修复。
丹尼斯,

您知道问题出在哪里吗?
MD XF

我知道我如何修复它(tcc必须在SELinux支持下构建),但是我不确定这样做是什么或为什么首先需要它。
丹尼斯


1

Jonaly Allan的果冻

原始代码:

œ?“¥ĊɲṢŻ;^»œ?@€⁸ḊFmṪ⁷

在线尝试!

输入:

1,2586391,2949273,3312154,3312154,1134001,362881,2223505,766081,1134001,1497601,3312154,1860601,140

说明:

主要是,有必要了解代码的作用。它要做的第一件事是接收字符串"!,Word Hel"(以及换行符以外的所有所需字符),并创建一堆排列的字符。输入指定置换编号,输入中的每一对置换将应用于首先应用第一个置换的字符串排除对。基本上是P2(P1(S)),P2(P2(S),P2(P3(S)),...,P2(PN(S)),P3(P1(S)),...,P3 (PN(S)),... ...,PN(P1(S)),...,PN(PN(S))。这些都连接在一起,然后最后一个输入被重用以占用每个PNth这个大字符串中的字符,所以我取PN = len(S)* N = 10 * N。这意味着我们将采用P2(P1(S))的第一个字符,P3(P1(S)的第一个字符)),一直到PN(P1(S))的第一个字符。为进一步简化,我让P1 = 1(即身份置换),然后选择将“ H”置换为第一个字符的P2就足够了位置,一个将“ e”排列到第一位置的P3,依此类推。幸运的是,小的排列数字(例如已经为PN选择的排列数字)不会影响字符串中的较早字符,因此PN留下“!” 在字符串的开头。(如果不是这样,则仍然可以通过选择其他P1来解决。)


它从14个排列的列表中提取14个排列,展平,出队,然后每140个字符。
乔纳森·艾伦

1

MD XF编写的C(TIO上的GCC)

4195875

在线尝试!

怎么样?

它尝试将第二个参数打印为字符串,这是我们可以在输入中确定的指针。碰巧的是,在位置存储器中4195875启动了"Hello, World!\n"字符串。

该数字是通过print("%p", "Hello, World!");在之前添加来确定的printf,将十六进制数字转换为十进制并在原始TIO上进行了尝试。但是,它向我显示了printf格式字符串。通过尝试一些数字,我发现该字符串位于格式字符串之前。

因此在内存中,它看起来像这样(作为C字符串):

Hello, World!\n\0%2$s\0

这也意味着对编译器的任何更新都可能破坏解决方案。






1

JavaScript(ES6),Voile

给定81个字符的限制,这可能不是预期的解决方案

global.g = ()=>"Hello, World!";
var str = "g";

在线尝试!


天才 通过全局操作传递一个char字符串。看来,它旨在解决方案
ЕвгенийНовиков

那不是预期的解决方案:(
Voile

现在我正在考虑它,我不认为在传递函数输入之前不允许这样做大量的事情,除非所说的东西也可以作为输入的一部分组成(例如,在函数内部(在内部评估),因为挑战要求您输入将导致“ Hello,World!”(不是完整程序)的输入。否则,几乎没有什么是安全的。所以我认为这个破解可能无效吗?
2017年

@Voile可能很好。我认为将任务视为输入必须独立(即无需更改外部系统)来阅读任务是很公平的-特别是如果这不是预期的解决方案时:)无需将警察标记为已破解。
Birjolaxew

1
我发表了一篇有关此问题的元文章。随时在此处进行一些讨论。
2017年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.